2010-08-29 23 views
3

我的主要问题是: 反射中是否可以区分某个委托类型的字段与事件用作存储字段的字段? 这就是问题:FieldInfo类是否包含有关它是否属于事件的信息,作为存储区?我无法找到任何可能显示的属性,也无法定位属性。反思:在运行时区分委托类型字段的事件字段

在下面的代码中,SomeField和SomeEvent的两个FieldInfos的相关属性都是相同的。所以我不知道如何根据它们是否是eventstoragefields来对FieldInfos进行排序。

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具有完全相同的名字,但我不知道这是否是万无一失坦率地说,我不会满足于这种解决办法。必须有更直接的方式。

回答

0

简答:不,没有傻瓜证明的方式来做到这一点。甚至没有必要成为事件的后台代理字段。如果有的话,它们之间的元数据没有任何联系。

+0

当然,必须有一种方式..... – JBSnorro 2010-08-31 15:08:58

0

在您的示例代码不编译,但是,这两个以下的事情:

class Program 
{ 
    public event Action<Program> 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<Program> SomeEvent; 

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

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

此示例代码与实际代码在某些重要方面有所不同吗?

+0

不,它没有区别。当然这就是我的意思。谢谢 – JBSnorro 2010-08-30 14:26:36

1

您已经定义场式的事件:

C#语言规范:

当编译一个类似字段的事件时,编译器会自动创建存储空间来保存委托,并创建访问器事件将事件处理程序添加或删除到委托字段。

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

Type.GetMember()

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

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

+0

这里有点不对劲。你说事件是公开的,而且存储区是私人的。但在我的代码中,我调用无参数的GetMembers,它只返回公共成员,并返回一个fieldInfo。不是我期望基于您的信息的eventInfo。 但试图回答我的主要问题(如何区分某个事件与某些委托类型的常规字段的存储字段)与您的信息:事件的存储字段始终是私有的,具有CompilerGeneratedAttribute,最重要的是,它具有声明类型中的事件的同名。它是否正确? – JBSnorro 2010-08-30 14:38:59

+0

你能给出代表问题的完整的可编译源代码示例吗? – desco 2010-08-30 14:51:36

+0

感谢您的快速回复。我在原来的帖子中这样做了。 – JBSnorro 2010-08-30 16:21:06

1

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

class Program { 
    public event Action<Program> SomeEvent; 
    public Action<Program> 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); 
    } 
} 
+0

它不起作用。它将返回事件字段的“字段”。 – 2015-01-28 18:03:01

+0

@MichaelLogutov,我无法重现那种行为。示例代码在单声道3.12上输出'eventField.MemberType:Event','normalField.MemberType:Field'。你在用什么,它输出什么? – sisve 2015-01-29 13:10:51

+0

对不起,我错了。它确实有效。我猜错了,因为GetFiels会得到MemberInfo.MemberType == Field的行为不一致。 – 2015-01-29 18:22:57