C# 如何筛选类事件的底层实现字段信息?

C# 如何筛选类事件的底层实现字段信息?,c#,.net,reflection,fieldinfo,C#,.net,Reflection,Fieldinfo,我希望获取一个类的所有字段,而不获取类事件的底层实现。 键入.GetFieldsBindingFlags。。。返回事件字段的NuderLiving委托。有人知道如何过滤它们吗?NET中的事件生成一个与事件类型相同的字段。此外,它们生成两个方法adder和remover,这两个方法与前缀为“add_”和“remove_”的字段具有相同的名称 为了筛选事件支持字段,可以删除与事件同名的字段。您可以确保不会使用与事件相同的名称定义任何字段,因为如果使用相同的名称定义另一个成员,编译器将无法编译 例如:

我希望获取一个类的所有字段,而不获取类事件的底层实现。
键入.GetFieldsBindingFlags。。。返回事件字段的NuderLiving委托。有人知道如何过滤它们吗?

NET中的事件生成一个与事件类型相同的字段。此外,它们生成两个方法adder和remover,这两个方法与前缀为“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是事件的支持字段的标记。我真的希望有人能为这个问题发布一个优雅而安全的解决方案:

你是什么意思?如果您有一个名为Container的对象,并且它有一个Container字段,您不想看到该字段吗?当使用Action委托反射名为NotifySomething的事件类型时,会在类中创建一个Action类型的私有字段,我不想得到它。我希望反射API提供更好的支持。我知道我可以这样做,但是我必须用不同的方式为VB实现它,事件X的底层字段是XEvent。@Izik Shmulewitz,你说得对,我甚至不知道VB会生成不同的后台字段。我添加了一些解决这个问题的代码,但它只适用于使用默认加法器和删除方法的事件。