簡體   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