我想获得一个类的所有字段,而不需要获取类事件的基础实现。 type.GetFields(BindingFlags ...)为事件字段返回亲密的委托。有谁知道如何过滤出来?如何过滤作为类事件基础实现的FieldInfos?
回答
.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是事件的支持字段的标记。我真的希望有人会发布一个优雅和安全的解决方案来解决这个问题:)
我希望能从反射API中得到更好的支持。我知道我可以这样做,但接下来我必须以不同的方式实现VB(称为X的事件的底层字段是XEvent)。 – 2010-06-05 11:33:15
@Izik Shmulewitz,你说得对,我甚至不知道VB会产生不同的后台字段。我添加了一些解决此问题的代码,但它仅适用于使用默认加法器和删除方法的事件。 – Elisha 2010-06-05 13:07:09
- 1. 以div节出现事件为基础
- 2. 爪哇 - 如何实现方法克隆为基础,派生类
- 3. 实现派生接口的基础件
- 4. 基础实体类。 NHibernate的
- 5. 使用SPDY作为SOA相关实现的基础传输
- 6. 如何在Python中实现shell作业控制基础?
- 7. 如何在非基于VO的ADF RichTable中实现过滤器?
- 8. 如何实现基于不同标准的收集过滤
- 9. 如何使用不同的基础实现实例化扩展类?
- 10. 过滤NSMutableArray的基础上过滤另一个NSMutableArray
- 11. 如何在asp.net中实现用户基础安全而不是角色基础?
- 12. 使用非抽象类作为基础
- 13. 过滤器是如何实现的?
- 14. 如何实现android的过滤器listview
- 15. 如何实现treetableview的过滤
- 16. 如何实现匹配的过滤器
- 17. Angularjs过滤器基础知识
- 18. 码头资源基础目录过滤
- 19. 是否有可能将现有的类作为.xsd文件的基础jaxb
- 20. WPF - 为基类实现System.ComponentModel.INotifyPropertyChanged
- 21. 如何建立基础和模式实验室,为Drupal工作?
- 22. 设计模式的基础上,实现
- 23. 如何基于关系实现Doctrine2过滤器?
- 24. 如何覆盖CSS类的基础类
- 25. 如何使用维度过滤事实?
- 26. 如何实现空间栏的actionListener作为行动事件
- 27. 如何实现REST API的基础servlet和Tomcat8与Spring/Hibernate的
- 28. 在Prolog中使用非基础事实?
- 29. 如何在php中实现类似Angular的过滤器功能?
- 30. 如何在其他基础上过滤Apache flink流?
你是什么意思?如果您有一个名为Container的对象并且它具有一个Container字段,那么您不希望看到该字段? – Kiril 2010-05-26 00:40:37
当使用Action委托来反映带有名为NotifySomething的事件的类型时,类中将创建一个类型为Action的私有字段,我不想获取它。 – 2010-05-27 10:48:40