2016-07-20 5 views
1

У меня есть класс следующим образом:Как получить поле поддержки Getter из PropertyInfo?

class Foo : PropertyChangedBase { 
    private int _property; 

    public int Property { 
     get { return _property; } 
     set { OnAssignPropertyChanged("Property",() => _property, value); } 
} 

PropertyChangedBase реализует INotifyPropertyChanged со следующими методами:

protected void OnAssignmentPropertyChanged<T>(string propertyName, Expression<Func<T>> fieldExpression, T value) 
    { 
     var get = fieldExpression.Compile(); 
     if (get().Equals(value)) 
     { 
      return; 
     } 

     // invoke set property method 
     SetProperty(fieldExpression, value); 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    private void SetProperty<T>(Expression<Func<T>> fieldExpression, T value) 
    { 
     if (fieldExpression == null) 
     { 
      throw new ArgumentNullException(nameof(fieldExpression)); 
     } 

     var memberExpression = fieldExpression.Body as MemberExpression; 
     if (memberExpression == null) 
     { 
      throw new ArgumentException("fieldExpression"); 
     } 

     var field = memberExpression.Member as FieldInfo; 
     if (field == null) 
     { 
      throw new ArgumentException("fieldExpression"); 
     } 

     field.SetValue(this, value); 
    } 

Я предпочел бы назвать:

OnAssignPropertyChanged(() => Property, value); 

Единственный способ это будет работать если я могу получить поле поддержки для свойства getter, а затем передать это SetProperty. Можно ли получить FieldInfo или целевой элемент из метода get свойства?

ответ

1

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

Посмотрите на ответ здесь: Find all property references using reflection. Цель немного отличается, но подход аналогичен для поиска ссылок на поля. Поскольку в ответе уже есть необходимый код, я просто опишу способ:

Все элементы метаданных в .Net ссылаются на токены. Чтобы получить маркеры, используемые внутри метода, вам необходимо проанализировать MethodBody (пропуская все, что вы не проверите), а затем resolve the found tokens in their module. Не забудьте использовать BitConverter при чтении токенов из потока для их устранения.

Но теперь к нижней стороне; единственный раз, когда вы действительно можете безопасно использовать это, чтобы найти поля поддержки свойства getter, - это когда вы находите простой метод get с четко определенной последовательностью операций opcode, такой как Ldfld, Ret или что-то в этом роде. Возможно, вы можете определить несколько шаблонов, которые компилятор C# будет испускать для простых и автоматически реализованных свойств. Если вы обнаружите что-то другое, нет другого способа уйти в отставку и выбросить исключение, потому что геттер может содержать любой код. Как всегда с отражением, используйте только белые списки, проверяйте условия, которые вы ожидаете, и бросайте исключения в любом другом случае, или вы рано или поздно столкнетесь с NullReferenceException.

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

+0

Звучит разумно. Вариант использования очень специфичен для классов, которые наследуются от базового класса. Основываясь на нашем руководстве по кодированию, мы можем обеспечить соблюдение правил использования. Благодарю. – IAbstract

1

Нет, в общем случае вы не может. Просто сравните два класса:

public class Test { 
    private int _propA; 
    private int _propB; 

    public int PropA {get { return _propA; }} 
    public int PropB {get { return _propB; }} 
} 

public class TestSwapped { 
    private int _propA; 
    private int _propB; 

    // please, notice swapped backing fields 
    public int PropA {get { return _propB; }} 
    public int PropB {get { return _propA; }} 
} 

вы получите одинаковые PropertyInfo[] и FieldInfo[] массивов, но различных полей отступающих

+0

Вам, конечно же, придется сравнивать тела аксессуаров. Это сложно, так как любой IL-код может быть там. Я построил в режиме Release ваш пример и попробовал 'typeof (TestSwapped) .GetProperty (« PropA »). GetMethod.GetMethodBody(). GetILAsByteArray()' и аналогичный для 'Test'. Он просто загружает «это» в стек, загружает соответствующее поле ('ldfld') из него и возвращает это. Разница была замечена в аргументе команды 'ldfld'. –

+0

@ Jeppe Stig Nielsen: havig * IL code *, конечно, мы можем узнать (или хотя бы предложить разумное предположение) поле поддержки в простых случаях (т. Е. 'Return _propB;'); в * общем случае *, однако * невозможно * (модификация модификации Алана Тьюринга). Например. get 'get {if (_propA> 0) return _propB; else return _propB + 1;} 'Первое поле, загруженное (зависит от компилятора), является полем' _propA' является '_propB' –

+0

@DmitryBychenko: отличная точка в свойствах. Моя реализация специфична для простых геттеров: 'get {return _field; } '... Модели или ViewModels, реализующие наше уведомление об изменении свойств, должны быть простыми геттерами. – IAbstract

0

Вы не можете. Свойство не может иметь полей поддержки или наборов полей поддержки. Даже свойство set не может иметь никаких полей поддержки.

public Int32 Prop 
{ 
set { Debug.WriteLine(value.ToString()); } 
get { return 1; } 
} 

Что вы ожидаете получить в FieldInfo?

+0

В свойствах с автоаксессуарами вы можете получить поля автоподдержки через отражение: например. { получить; задавать; } имеет поля автоподдержки. Таким образом, я бы предположить, вы могли бы получить поле подкладочный, если, как в моем примере, добытчик фактически возвращает поле; – IAbstract

+0

Ну, вы не можете, насколько я знаю. –

+0

Возможно, это возможно, но это огромная работа для компилятора. Хотя простые случаи просты, случаи легко усложняются. –

0

Недвижимость - это всего лишь синтаксический сахар для пары методов set/get или мутаторов. Быть методом позволяет им содержать столько кода, сколько необходимо, в том числе быть просто пустым и, конечно же, нет необходимости иметь поле поддержки из перспективы компилятора.

 Смежные вопросы

  • Нет связанных вопросов^_^