2010-05-25 26 views
2

我想獲得一個類的所有字段,而不需要獲取類事件的基礎實現。 type.GetFields(BindingFlags ...)爲事件字段返回親密的委託。有誰知道如何過濾出來?如何過濾作爲類事件基礎實現的FieldInfos?

+0

你是什麼意思?如果您有一個名爲Container的對象並且它具有一個Container字段,那麼您不希望看到該字段? – Kiril 2010-05-26 00:40:37

+0

當使用Action委託來反映帶有名爲NotifySomething的事件的類型時,類中將創建一個類型爲Action的私有字段,我不想獲取它。 – 2010-05-27 10:48:40

回答

1

.NET中的事件生成一個與事件相同和類型的字段。另外,它們生成兩種方法(加法器和去除器,它們與具有前綴'add_'和'remove_'的字段名稱相同)。

爲了過濾事件支持字段,您可以刪除與事件同名的字段。您可以確定沒有字段將被定義爲具有與事件相同的名稱,因爲如果使用相同名稱定義了另一個成員,編譯器將會使編譯失敗。

例如:

public IEnumerable<FieldInfo> FilterBackingEventFields(Type type) 
{ 
    List<string> eventNames = type 
     .GetEvents().Select(eventInfo => eventInfo.Name).ToList(); 

    FieldInfo[] fieldInfos = type 
     .GetFields(BindingFlags.NonPublic | 
        BindingFlags.Public | 
        BindingFlags.Instance); 

    return fieldInfos.Where(fieldInfo => !eventNames.Contains(fieldInfo.Name)); 
} 

用例:

public class ClassWithEventAndField 
{ 
    public event EventHandler MyEvent; 
    public int MyField; 
} 

[Test] 
public void TestFieldsFilter() 
{ 
    IEnumerable<FieldInfo> fields = 
     FilterBackingEventFields(typeof(ClassWithEventAndField)); 

    FieldInfo expectedField = typeof(ClassWithEventAndField).GetField("MyField"); 
    Assert.That(fields, Is.EquivalentTo(new[] { expectedField })); 
} 

編輯:增加了支持與VB工作和C#

此代碼將工作在自動生成的事件(定製加法器或移除器將破壞代碼)。這也是一個有風險的代碼,它對加法器方法生成和編譯的方式做了一些假設。我將這些代碼發佈爲「學術」信息,我不會在生產代碼中使用它。

public IEnumerable<FieldInfo> FilterBackingEventFields(Type type) 
{ 
    List<int> backingFieldsTokens = type 
     .GetEvents().Select(eventInfo => MetadataToken(eventInfo)).ToList(); 

    FieldInfo[] fieldInfos = type 
     .GetFields(BindingFlags.NonPublic | 
        BindingFlags.Public | 
        BindingFlags.Instance); 

    return fieldInfos 
    .Where(fieldInfo => !backingFieldsTokens.Contains(fieldInfo.MetadataToken)); 
} 

private static int MetadataToken(EventInfo eventInfo) 
{ 
    MethodInfo adderMethod = eventInfo.GetAddMethod(); 
    int fieldToken = 
     adderMethod.GetMethodBody().GetILAsByteArray()[3] | 
     adderMethod.GetMethodBody().GetILAsByteArray()[4] << 8 | 
     adderMethod.GetMethodBody().GetILAsByteArray()[5] << 16 | 
     adderMethod.GetMethodBody().GetILAsByteArray()[6] << 24; 

    return fieldToken; 
} 

這裏假設的是,加法器方法體中的字節3-6是事件的支持字段的標記。我真的希望有人會發佈一個優雅和安全的解決方案來解決這個問題:)

+0

我希望能從反射API中得到更好的支持。我知道我可以這樣做,但接下來我必須以不同的方式實現VB(稱爲X的事件的底層字段是XEvent)。 – 2010-06-05 11:33:15

+0

@Izik Shmulewitz,你說得對,我甚至不知道VB會產生不同的後臺字段。我添加了一些解決此問題的代碼,但它僅適用於使用默認加法器和刪除方法的事件。 – Elisha 2010-06-05 13:07:09

相關問題