2010-05-25 25 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

相关问题