Свойство C#, можно ли обойти определение get без определения set (без резервной переменной)?

допустим, у вас есть класс С 300 свойствами без вспомогательных переменных, каждое из этих свойств возвращает decimal / double.

пример:

public decimal MathValue { get; set; }

теперь вы решили, что каждое из этих значений должно быть округлено.

Я ищу самый простой способ рефакторинга этого без необходимости переписывать все эти свойства.

что-то, из этого эквивалента, который действительно работает :D:

public decimal MathValue { get {return Math.Round(MathValue);} set; }

8 ответов


вы можете создать новый тип значения, который притворяется десятичным, но возвращает округленное значение. Что-то вроде этого:--4-->

struct RoundedDecimal
{
    public decimal Value { get; private set; }

    public RoundedDecimal(decimal value) : this()
    {
        this.Value = value;
    }

    public static implicit operator decimal(RoundedDecimal d)
    {
        return Math.Round(d.Value);
    }
}

каждое свойство в вашем классе должно иметь тип RoundedDecimal вместо decimal.


нет. Если вам нужна какая-либо пользовательская логика в getter или setter, вы не можете использовать auto-properties.


самый простой способ рефакторинга кода? Вот что бы я сделал:--1-->

  1. откройте Notepad++ (получите его, если у вас его нет)
  2. скопируйте / вставьте все свойства класса в пустую текстовую область.
  3. поместите курсор в начало первой строки: открытый десятичный MathValue1 { get; set;}
  4. начать запись макроса (нажмите кнопку запись на панели инструментов)
  5. удерживайте ctrl + Стрелка вправо (называется "Слово вправо") 3 раза, чтобы положить курсор в начале имени свойства.
  6. do shift + ctrl + Стрелка вправо 1 раз и сделать копию, чтобы поместить имя свойства в буфер обмена
  7. слово вправо еще 3 раза, чтобы поместить курсор после "get"
  8. удалите двоеточие после get и начните вводить " { return Math.Круглый (_"
  9. сделать пасту 10 Тип "); }"
  10. слово вправо еще 2 раза, чтобы поместить курсор после "set"
  11. удалить точку с запятой после набора и начните вводить " { _"
  12. выполнить вставить
  13. type " = value;}
  14. нажмите клавишу End, чтобы переместить курсор в конец строки
  15. нажмите клавишу со стрелкой вправо, чтобы получить курсор в начало следующей строки.
  16. нажмите кнопку стоп, чтобы завершить макрос (квадратная кнопка на панели инструментов)
  17. Нажмите кнопку" Запустить макрос несколько раз "(значок с двойной стрелкой на панели инструментов) и скажите " запустить до конца файл"
  18. скопируйте / вставьте полученный текст обратно в класс, чтобы заменить исходные определения свойств.

теперь вам нужно определить набор соответствующих частных переменных, которые начинаются с подчеркивания, но в остальном имеют те же имена, что и свойства. Начните с новой копии свойств из вашего класса и выполните аналогичный набор шагов, как описано выше.

Я предполагаю, что каждая строка начинается с 2 вкладок и нет пустые строки между свойствами.

вместо того, чтобы каждый вызов свойства Math.Раунд, вы можете рассмотреть вопрос об определении вашей собственной функции полезности, которую они все называют, так что если вам нужно изменить его снова, вы можете просто изменить его в одном месте.


вы можете создать производную этого класса, которая переопределяет GET и возвращает округленные значения. Затем вам нужно будет изменить базовое свойство, чтобы оно было виртуальным. Но это позволит вам определить get без определения набора и использования автоматических свойств.

public class Base
{
    public virtual decimal MathValue { get; set; }
}

public class Derived : Base
{
    public override decimal MathValue
    {
        get { return Math.Round(base.MathValue); }
    }
}

но что произойдет, если клиент не хочет округленное значение? т. е. какой-то новый клиентский код устанавливает десятичное число и ожидает, что "точное" значение вернется?

Если некоторым клиентам действительно нужен округленный вывод вызова свойства, то клиент должен обработать это и оставить ваш класс в покое.


Visual Studio использовал встроенный фрагмент кода" prop", который генерировал бы что-то вроде следующего кода:

    private decimal _MathValue;

    public decimal MathValue
    {
        get { return _MathValue; }
        set { _MathValue = value; }
    }

Это позволит вам большую часть пути к полному решению, но с 2008 года он теперь генерирует версию автоматического свойства:

    public decimal MathValue { get; set; }

Я еще не пробовал этого, но вот предложение по созданию собственного фрагмента кода, чтобы получить версию VS 2005 фрагмента кода "prop" обратно:


один из вариантов - использовать аспектно-ориентированное программирование для перехвата вызовов свойств при возврате и округления возвращаемого значения перед передачей управления вызывающему объекту.


вы могли бы сделать это с помощью PostSharp или некоторые другие .Нетто-основе АОП. Вот это MethodExecutionEventArgs.Аргумент returnvalue собственность это говорит о том, что его можно использовать для "изменения возвращаемого значения..."

это сделает это:

[Serializable]
public class RoundingAttribute : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionEventArgs eventArgs)
    {
        base.OnExit(eventArgs);
        eventArgs.ReturnValue = Math.Round((double)eventArgs.ReturnValue, 2);
    }
}

class MyClass
{
    public double NotRounded { get; set; }

    public double Rounded { [Rounding] get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var c = new MyClass
                {
                    Rounded = 1.99999, 
                    NotRounded = 1.99999
                };

        Console.WriteLine("Rounded = {0}", c.Rounded); // Writes 2
        Console.WriteLine("Not Rounded = {0}", c.NotRounded);  // Writes 1.99999
    }
}