reflection:在运行时将事件字段与委托类型字段区分开来

我的主要问题是:在reflection中是否有可能将某个委托类型的字段与事件用作存储字段的字段区分开来? 这归结为一个问题:FieldInfo类是否包含有关它是否属于某个事件的信息,如存储字段? 我找不到任何可能告诉的属性,也没有找到属性属性。

在下面的代码中,SomeField和SomeEvent的FieldInfos的相关属性是相同的。 因此我不知道如何根据FieldInfos是否为eventstoragefield来对其进行排序。

using System; using System.Reflection; using System.Runtime.CompilerServices; namespace Test { class Program { public Action SomeField; public event Action SomeEvent; static void Main(string[] args) { FieldInfo[] fields = typeof(Program).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo fi in fields) Console.WriteLine(string.Format("FieldName: {0}, Accessibility: {1}, Has Attributes: {2}.", fi.Name, fi.Attributes, fi.GetCustomAttributes(true).Length != 0)); Console.ReadLine(); } } } 

一种解决方案是搜索名称完全相同的eventInfo,但我不知道这是否万无一失,坦白说,我不满意这个解决方案。 必须有一个更直接的方式。

简答:不,没有万无一失的方法可以做到这一点。 甚至不必是事件的支持委托字段。 如果存在,则它们之间的元数据没有关联。

您已定义了类似字段的事件:

C#语言规范:

编译类似字段的事件时,编译器会自动创建存储以保存委托,并为事件创建访问器,以便向委托字段添加或删除事件处理程序。

编译器如何为存储字段生成名称未指定。 通常,此字段名称与事件名称匹配,因此您将拥有两个具有相同名称的成员(示例中为SomeName),但不同的成员类型和不同的可见性(事件 – 公共,字段 – 私有)。

Type.GetMember() :

GetMembers方法不按特定顺序返回成员,例如按字母顺序或声明顺序。 您的代码不得依赖于返回成员的顺序,因为该顺序会有所不同。

如果你在没有参数的情况下重载GetMembers(),那么它应该只返回公共成员 – 事件。 但是,如果您使用另一个重载(接受BindingFlags)与BindingFlags.NonPublic – 那么它将以未指定的顺序返回字段和事件,因此您不能依赖您获得的第一个元素将是事件。

使用MemberInfo.MemberType属性。 它将返回Field / Event。 RtFieldInfo是表示字段(fieldInfo.GetType())的FieldInfo对象的类型,而不是字段的类型(fieldInfo.MemberType)。

 class Program { public event Action SomeEvent; public Action SomeField; static void Main(string[] args) { var members = typeof (Program).GetMembers(); var eventField = members.First(mi => mi.Name == "SomeEvent"); var normalField = members.First(mi => mi.Name == "SomeField"); Console.WriteLine("eventField.MemberType: {0}", eventField.MemberType); Console.WriteLine("normalField.MemberType: {0}", normalField.MemberType); } } 

您的示例中的代码无法编译,但是,以下两项都是:

 class Program { public event Action SomeEvent; static void Main(string[] args) { var test = typeof(Program).GetMembers().First((mi) => mi.Name == "SomeEvent"); Console.WriteLine(test.GetType()); } } 

要么

 class Program { public event Action SomeEvent; static void Main(string[] args) { var test = typeof(Program).GetMembers().First((mi) => {return mi.Name == "SomeEvent";}); Console.WriteLine(test.GetType()); } } 

两者都产生基类MemberInfo的结果,因为这是GetMember()返回的结果,具有输出到控制台的实际类型的RuntimeEventInfo

此示例代码是否与某些重要方面的实际代码不同?