Рефлексия конструкторов, полей и свойств

25

В предыдущей статье мы рассмотрели пример использования рефлексии методов, таким же образом можно получить информацию о полях, свойствах и интерфейсах класса с помощью методов GetField() и GetInterfaces. Давайте модифицируем программу из предыдущей статьи и добавим обобщенные методы в класс Reflect, отображающие информацию о полях, свойствах и интерфейсах, добавив реализацию интерфейса в класс MyTestClass:

...

    interface IInfoClass
    {
        double Sum();
        void Info();
        void Set(double d1, double d2);
    }

    // Тестовый класс, содержащий некоторые конструкции
    class MyTestClass : IInfoClass
    {
       ...
// В данном классе определены методы использующие рефлексию
    class Reflect
    {
        // Информация о полях и реализуемых интерфейсах 
        public static void FieldInterfaceInfo<T>(T obj) where T : class
        {
            Type t = typeof(T);
            Console.WriteLine("\n*** Реализуемые интерфейсы ***\n");
            var im = t.GetInterfaces();
            foreach (Type tp in im)
                Console.WriteLine("--> "+tp.Name);
            Console.WriteLine("\n*** Поля и свойства ***\n");
            FieldInfo[] fieldNames = t.GetFields();
            foreach (FieldInfo fil in fieldNames)
                Console.Write("--> "+fil.ReflectedType.Name + " " + fil.Name + "\n");
        }

        // Данный метод выводит информацию о содержащихся в классе методах
        public static void MethodReflectInfo<T> (T obj) where T: class
        {
            Type t = typeof(T);
            // Получаем коллекцию методов
            MethodInfo[] MArr = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
            Console.WriteLine("*** Список методов класса {0} ***\n",obj.ToString());

            // Вывести методы
            foreach (MethodInfo m in MArr)
            {
                Console.Write(" --> "+m.ReturnType.Name + " \t" + m.Name + "(");
                // Вывести параметры методов
                ParameterInfo[] p = m.GetParameters();
                for (int i = 0; i < p.Length; i++)
                {
                    Console.Write(p[i].ParameterType.Name + " " + p[i].Name);
                    if (i + 1 < p.Length) Console.Write(", ");
                }
                Console.Write(")\n");
            }
        }
    }

    class Program
    {
        static void Main()
        {
            MyTestClass mtc = new MyTestClass(12.0,3.5);
            Reflect.MethodReflectInfo<MyTestClass>(mtc);
            Reflect.FieldInterfaceInfo<MyTestClass>(mtc);

            Console.ReadLine();
        }
    }
Использование рефлексии полей и интерфейсов

Следует иметь в виду, что большинство из "получающих", т.е. get-методов в System.Type (GetMethods(), GetInterfaces() и т.д.), имеют перегруженные версии, принимающие значения из перечисления BindingFlags. Это позволяет более точно указать, поиск чего должен производиться (например, только статических членов, только общедоступных членов, включая приватные члены, и т.д.).

Сильные стороны рефлексии проявляются наиболее заметно лишь в том случае, если объект создается динамически во время выполнения. И для этого необходимо получить сначала список конструкторов, а затем экземпляр объекта заданного типа, вызвав один из этих конструкторов. Такой механизм позволяет получать во время выполнения экземпляр объекта любого типа, даже не указывая его имя в операторе объявления.

Конструкторы конкретного типа получаются при вызове метода GetConstructors() для объекта класса Type. Ниже приведена одна из наиболее часто используемых форм этого метода:

ConstructorInfо[] GetConstructors()

Метод GetConstructors() возвращает массив объектов класса ConstructorInfо, описывающих конструкторы. Класс ConstructorInfo является производным от абстрактного класса MethodBase, который в свою очередь наследует от класса MemberInfo. В нем также определен ряд собственных методов. К их числу относится интересующий нас метод GetConstructors(), возвращающий список параметров, связанных с конструктором. Этот метод действует таким же образом, как и упоминавшийся ранее метод GetParameters(), определенный в классе MethodInfo.

Как только будет обнаружен подходящий конструктор, для создания объекта вызывается метод Invoke(), определенный в классе ConstructorInfo. Ниже приведена одна из форм этого метода:

object Invoke(object[] parameters)

Любые аргументы, которые требуется передать методу, указываются в массиве parameters. Если же аргументы не нужны, то вместо массива parameters указывается пустое значение (null). Но в любом случае количество элементов массива parameters должно совпадать с количеством передаваемых аргументов, а типы аргументов — с типами параметров. Метод Invoke() возвращает ссылку на сконструированный объект.

Пройди тесты
Лучший чат для C# программистов