繁体   English   中英

如何从PropertyInfo获取Getter支持字段?

[英]How to get Getter backing field from 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 是否可以从属性get方法获取FieldInfo或目标成员?

作为一般答案,是的,你可以做到,至少在受控条件下。 但是你唯一应该这样做的情况就是当你绝对确定自己在做什么而且只有有限的支持时,因为有些情况你无法处理。

看看这里的答案: 使用反射查找所有属性引用 目标有点不同,但方法类似于查找字段引用。 由于答案已经包含了必要的代码,我将概述要走的路:

.Net中的所有元数据项都由标记引用。 要获取在方法中使用的标记,您必须解析MethodBody (通过跳过您不会检查的所有内容),然后在其模块中解析找到的标记 记住在从流中读取令牌时使用BitConverter来解决它们。

但现在向下; 唯一一次你可以真正安全地使用它来查找属性getter的支持字段,就是当你找到一个简单的get方法时,有一个定义良好的操作码序列,如Ldfld,Ret或类似的东西。 也许您可以定义一些C#编译器将为简单和自动实现的属性发出的模式。 如果你发现任何不同的东西,没有别的方法可以辞职并抛出异常,因为getter可以包含任何代码。 就像使用反射一样,只使用白名单方法,检查您期望的条件并在任何其他情况下抛出exeptions,否则您迟早会遇到NullReferenceException。

如果这是值得的,你可以自己决定,但一般来说你可以这样做.Net 2.0,甚至不需要花哨的外部库。

不,一般情况下你不能 只比较两个类:

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[]数组但不同的支持字段

你不能。 属性可以没有支持字段或支持字段集。 即使是set属性也根本没有后备字段。

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

您期望在FieldInfo中获得什么?

属性只是一对set / get方法或mutator的语法糖。 作为一种方法,它们可以根据需要包含尽可能多的代码,包括只是空的,当然,不需要从编译器角度来看具有支持字段。

在针对不同的问题进行此操作时,以下是针对简单情况的扩展方法 - 自动生成的支持字段,或仅返回支持字段的get:

public static class MethodInfoExt {
    const int IL_ldarg0 = 0x02;
    const int IL_ldfld = 0x7B;

    public static FieldInfo FieldInfoFromGetAccessor(this MethodInfo getAccessorMI) {
        var body = getAccessorMI.GetMethodBody().GetILAsByteArray();
        if (body[0] == IL_ldarg0 && body[1] == IL_ldfld) {
            var fieldToken = BitConverter.ToInt32(body, 2);
            return getAccessorMI.DeclaringType.Module.ResolveField(fieldToken);
        }
        else
            return default;
    }    
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM