我想获取一个类的所有字段,但不包括获取该类事件的底层实现。 type.GetFields(BindingFlags...)会返回事件字段的底层委托。有谁知道如何过滤掉它们?
我想获取一个类的所有字段,但不包括获取该类事件的底层实现。 type.GetFields(BindingFlags...)会返回事件字段的底层委托。有谁知道如何过滤掉它们?
.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;
}