views:

65

answers:

4

The main question I have is: Is it possible in reflection to distinguish a field of some delegate type from a field which is used by an event as storagefield? That comes down to the question: does the FieldInfo class contain information about whether it belongs to an event, as storagefield ? I can't find any properties which might tell, nor custum attributes.

In the code below, the relevant properties of both FieldInfos of SomeField and SomeEvent are identical. So I don't know how to sort FieldInfos based on whether they are eventstoragefields or not.

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();
        }
    }
}

One solution is to search for an eventInfo with exactly the same name, but I don't know whether that is foolproof and frankly, I would not be satisfied with that solution. There must be a more direct way.

A: 

The code in your example doesn't compile, however, both of the following do:

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());
    }
}

or

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());
    }
}

Both produce a result of base class MemberInfo since that is what GetMember() returns, with an actual type of RuntimeEventInfo, which is output to the console.

Does this example code differ from the actual code in some significant way?

David Culp
No it does not differ. Ofcourse that is what I meant. Thank you
JBSnorro
A: 

You have defined field-like event:

C# language spec:

When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field.

How compiler generates name for storage field is unspecified. Usually this name of field matches with the name of event, so you will have two members with the same name (SomeName in your example), but different member types and different visibility (event - public, field - private).

Type.GetMember():

The GetMembers method does not return members in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which members are returned, because that order varies.

If you take overload of GetMembers() without parameters then it should return only public members - event. However if you use another overload (that accepts BindingFlags) with BindingFlags.NonPublic - then it will return both field and event in unspecified order, so you can't rely that first element you get will be event.

desco
Something is wrong here. You say the event is public, and the storagefield private. But in my code I call the parameterless GetMembers, which only returns public members, and a fieldInfo is returned. Not the eventInfo that I would expect based on your information.But an attempt to answer my main question(How to distinguish a storagefield for an event from a regular field of some delegatetype) with your information: a storagefield for an event is always private, has the CompilerGeneratedAttribute and most importantly, it has the same name of an event in the declaring type. Is this correct?
JBSnorro
Can you give complete compilable sample of source code that represents the problem?
desco
Thank you for the quick response. I have done so in my original post.
JBSnorro
A: 

Use the MemberInfo.MemberType property. It will return Field/Event. RtFieldInfo is the type of the FieldInfo object representing the field (fieldInfo.GetType()), not the type of field (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);
    }
}
Simon Svensson
A: 

Short answer: No, there's no fool proof way to do it. There doesn't even have to be a backing delegate field for an event. And if there is, there's no connection in metadata between them.

Mattias S
Surely there must be a way.....
JBSnorro