Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflection: Distinguishing event-field from field of delegate type on runtime

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.

like image 334
JBSnorro Avatar asked Nov 24 '25 16:11

JBSnorro


2 Answers

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.

like image 126
desco Avatar answered Nov 27 '25 07:11

desco


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);
    }
}
like image 35
sisve Avatar answered Nov 27 '25 07:11

sisve



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!