Отражение: выделение поля события из поля типа делегата во время выполнения - PullRequest
3 голосов
/ 29 августа 2010

Главный вопрос, который у меня есть: возможно ли в рефлексии отличить поле некоторого типа делегата от поля, которое используется событием в качестве поля хранения?Это сводится к вопросу: содержит ли класс FieldInfo информацию о том, принадлежит ли он к событию, как поле хранения?Я не могу найти ни свойств, которые могли бы рассказать, ни атрибутов custum.

В приведенном ниже коде соответствующие свойства обоих FieldInfos SomeField и SomeEvent идентичны.Поэтому я не знаю, как сортировать FieldInfos, основываясь на том, являются ли они eventstoragefields или нет.

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 с точно таким же именем, но я не знаю, является ли этоЯ не был бы удовлетворен таким решением.Должен быть более прямой путь.

Ответы [ 4 ]

2 голосов
/ 29 августа 2010

Вы определили похожее на поле событие:

Спецификация языка C #:

При компиляции события, подобного полю, компилятор автоматически создает хранилище для хранения делегата и создает средства доступа для события, которые добавляют или удаляют обработчики событий в поле делегата.

Как компилятор генерирует имя для поля хранения, не указано. Обычно это имя поля совпадает с именем события, поэтому у вас будет два члена с одинаковым именем (SomeName в вашем примере), но с разными типами элементов и разной видимостью (событие - общедоступное, поле - частное).

Type.GetMember ()

Метод GetMembers не возвращает членов в определенном порядке, например в алфавитном порядке или в порядке объявления. Ваш код не должен зависеть от порядка, в котором возвращаются участники, потому что этот порядок варьируется.

Если вы берете перегрузку GetMembers () без параметров, тогда он должен возвращать только открытые члены - событие. Однако если вы используете другую перегрузку (которая принимает BindingFlags) с BindingFlags.NonPublic - тогда она будет возвращать как поле, так и событие в неопределенном порядке, поэтому вы не можете полагать, что первый полученный элемент будет событием.

2 голосов
/ 29 августа 2010

Используйте свойство MemberInfo.MemberType . Он вернет Поле / Событие. RtFieldInfo - это тип объекта FieldInfo, представляющий поле (fieldInfo.GetType ()), а не тип поля (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 голосов
/ 31 августа 2010

Краткий ответ: Нет, нет надежного способа сделать это. Там даже не должно быть поля делегата поддержки для события. И если есть, в метаданных нет никакой связи между ними.

0 голосов
/ 29 августа 2010

Код в вашем примере не компилируется, однако, оба следующих кода:

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, который выводится на консоль.

Отличается ли этот пример кода от реального кода каким-либо существенным образом?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...