Рефлексия типов. Получение метаданных типа. Пространство имен System.Reflection. Класс System.Type. Способы получения информации о типе

Рефлексия типов. Получение метаданных типа. Пространство имен System.Reflection. Класс System.Type. Способы получения информации о типе. Оператор typeof


Содержание



1. С помощью каких инструментов Microsoft Visual Studio можно проанализировать основную информацию о сборке?

В состав Microsoft Visual Studio входят специальные утилиты ildasm.exe и reflector.exe. Эти утилиты позволяют анализировать:

  • CIL-код сборки;
  • метаданные типов, которые реализованы в сборке;
  • манифест сборки для любого двоичного файла .NET.

Кроме того, в Microsoft Visual Studio эту же информацию можно получить программно с помощью пространства имен System.Reflection.

 

2. Какие типы можно полностью описывать с помощью метаданных?

С помощью метаданных можно полностью описывать следующие типы:

  • классы (class);
  • интерфейсы (interface);
  • структуры (struct);
  • перечисления (enum);
  • делегаты (delegate).

 

3. Что такое рефлексия в .NET?

Рефлексия (reflection) в .NET – это процесс выявления метаданных (типов) во время выполнения программы в виде объектной модели. Другими словами, рефлексия – это средство для получения сведений о типе данных. Рефлексия позволяет получить точно такую же информацию о метаданных типов, какую можно получить с помощью утилиты ildasm.exe (IL Disassembler).

Рефлексия позволяет получать перечень всех типов, которые помещаются внутри:

  • исполняемого модуля *.exe;
  • файла сборки *.dll;
  • файлов с расширениями *.mod и *.mdl в случае многофайловой сборки.

 

4. Какие преимущества применения рефлексии в программах?

С помощью средств рефлексии (класс System.Type) можно получить данные о типах и их характеристике в сборке во время выполнения программы. Это дает следующие преимущества:

  • можно создавать типы и вызвать их методы без предыдущих знаний об именах, которые помещаются в этих типах. Это реализует так называемая динамическая идентификация типов;
  • не нужно на этапе компиляции знать информацию о типе, из которого будут вытягиваться метаданные. Достаточно знать только название типа. Название типа задается в строке String(), которая есть общедоступной в любом месте;
  • представление типов, которые вытягиваются из сборки, в виде удобной объектной модели.

 

5. В какой сборке и каком пространстве имен реализована рефлексия в C# .NET?

В C# .NET рефлексия реализована в пространстве имен System.Reflection, которое поставляется в составе сборки mscorlib.dll.

Чтобы в программе на C# использовать рефлексию, нужно подключить пространство имен System.Reflection

using System.Reflection;

 

6. Перечень и назначение наиболее важных типов из пространства имен System.Reflection

Пространство имен System.Reflection имеет много типов для реализации рефлексии. Однако, наиболее важными есть следующие:

  • Assembly – абстрактный класс. Он содержит статические методы работы со сборкой. Эти методы позволяют, например, загружать сборку;
  • AssemblyName – это есть класс, который содержит информацию которая используется для идентификации сборки. Например: номер версии сборки, информация о культуре и т.п.;
  • EventInfo – абстрактный класс. Содержит информацию о заданном событии;
  • FieldInfo – абстрактный класс. Может содержать информацию о заданных членах данных класса;
  • MemberInfo – абстрактный класс. Содержит информацию об общем поведении для классов (типов) EventInfo, FieldInfo, MethodInfo и PropertyInfo;
  • MethodInfo – абстрактный класс. Содержит информацию о заданном методе;
  • Module – абстрактный класс. Позволяет получить информацию о заданном модуле в случае многофайловой сборки;
  • ParameterInfo –   класс, который содержит информацию о заданном параметре в заданном методе;
  • PropertyInfo – абстрактный класс. Содержит информацию о заданном свойстве.

Чтобы получить информацию о заданном классе, используются методы класса System.Type, которые возвращают результат в виде массивов или отдельных классов вышеприведенных типов (Assembly, MethodInfo, ParameterInfo и т.д.).

 

7. Какое основное назначение класса System.Type? Как класс System.Type связан с рефлексией?

Класс System.Type есть полезным, когда нужно изучать метаданные некоторого типа (класса, интерфейса, структуры, перечисления, делегата). Класс System.Type инкапсулирует в себе тип данных. Методы класса System.Type возвращают типы из пространства имен System.Reflection.

Класс System.Type служит основой рефлексии. Благодаря методам класса System.Type можно определять информацию об используемых типах во время выполнения программы. Затем эту информацию можно анализировать, обрабатывать в зависимости от поставленной задачи.

 

8. Как получить информацию о типе в программе? Какие существуют способы программного получения информации о типе?

В C# .NET существует три способа программного получения информации о типе:

  1. Использование метода System.Object.GetType(). В этом случае метод возвращает метаданные текущего объекта типа (см. п. 9).
  2. Использование средства typeof(). В этом случае создавать объект типа (например, объект класса) не нужно. Достаточно иметь объявленный тип (см. п. 10).
  3. Использование статического метода System.Type.GetType(). Этот подход не нуждается в объявлении типа, информацию о котором нужно получить (см. п. 11). Достаточно знать только имя этого типа.

 

9. Каким образом можно получить информацию о типе с помощью метода System.Object.GetType()? Пример

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

Например, чтобы использовать этот способ для класса нужно:

  • сначала создать объект класса с помощью оператора new;
  • вызвать метод класса obj.GetType(), где obj – имя объекта данного класса.

Предварительно, в начале программного модуля может быть подключено пространство имен System.Reflection:

using System.Reflection;

Пример.

Задано объявление класса MathFunctions, который содержит 3 метода и 3 члена данных:

  • метод Min2() – находит минимум между двумя значениями;
  • метод Min3() – находит минимум между тремя значениями;
  • метод Max2() – находит максимум между двумя значениями;
  • внутренние члены данных класса с именами a, b, c.
class MathFunctions
{
    public int a, b, c; // члены данных класса

    // минимум между двумя значениями
    public int Min2(int a, int b)
    {
        if (a < b) return a;
        return b;
    }

    // минимум между тремя значениями
    public int Min3(int a, int b, int c)
    {
        int min = a;
        if (min > b) min = b;
        if (min > c) min = c;
        return min;
    }

    // максимум между двумя значениями
    public int Max2(int a, int b)
    {
        if (a < b) return b;
        return a;
    }
}

Получить перечень методов класса MathFunctions программным путем можно следующим образом

class Program
{
    static void Main(string[] args)
    {
        // получить значение типа
        MathFunctions mf = new MathFunctions();
        Type tp = mf.GetType();

        // взять перечень методов из класса MathFunctions
        MethodInfo[] mi = tp.GetMethods();

        // получить названия методов - упрощенный вариант
        string s1 = mi[0].Name; // s1 = "Min2"
        string s2 = mi[1].Name; // s2 = "Min3"
        string s3 = mi[2].Name; // s3 = "Max2"

        Console.WriteLine("Method1 = {0}", s1); // Method1 = Min2
        Console.WriteLine("Method2 = {0}", s2); // Method2 = Min3
        Console.WriteLine("Method3 = {0}", s3); // Method3 = Max2
    }
}

В данном примере класс MathFunctions может быть реализован

  • в одном и том же пространстве имен;
  • в другой сборке. В этом случае сборка с объявленным классом может быть подключена в разделе References а также директивой using.

 

10. Каким образом получить информацию о типе с помощью средства typeof? Пример

Типом может быть класс, интерфейс, структура, перечисление, делегат. Чтобы получить информацию о типе с помощью средства typeof, равно как и в предшествующем пункте, нужно располагать информацией о типе на этапе компиляции.

Например, чтобы использовать этот способ для класса, не нужно предварительно создавать объект класса. В общем случае, строка, которая получает информацию о некотором классе, имеет следующий вид:

Type tp = typeof(ClassName);

где ClassName – имя некоторого класса, для которого создается объект с именем tp, содержащий информацию об этом классе.

Предварительно, в начале программного модуля должно быть подключено пространство имен System.Reflection:

using System.Reflection;

Пример. Пусть задан класс MathFunctions, объявленный в п. 9. Класс содержит 3 метода с именами Min2(), Min3(), Max2() и 3 внутренние переменные с именами a, b, c.

Тогда, получение информации о методах и внутренниих переменных класса с использованием средства typeof() может быть следующим:

...

class Program
{
    static void Main(string[] args)
    {
        // получить значение типа
        Type tp = typeof(MathFunctions);

        // взять перечень методов из класса MathFunctions
        MethodInfo[] mi = tp.GetMethods();

        // получить названия методов
        string m1 = mi[0].Name; // m1 = "Min2"
        string m2 = mi[1].Name; // m2 = "Min3"
        string m3 = mi[2].Name; // m3 = "Max2"

        // взять перечень внутренних данных класса
        FieldInfo[] fi = tp.GetFields();

        string f1 = fi[0].Name; // название внутренней переменной a, f1 = "a"
        string f2 = fi[1].Name; // f2 = "b"
        string f3 = fi[2].Name; // f3 = "c"

        Console.WriteLine("Method1 = {0}", m1); // Method1 = Min2
        Console.WriteLine("Method2 = {0}", m2); // Method2 = Min3
        Console.WriteLine("Method3 = {0}", m3); // Method3 = Max2

        Console.WriteLine("Field1 = {0}", f1); // Field1 = a
        Console.WriteLine("Field2 = {0}", f2); // Field2 = b
        Console.WriteLine("Field3 = {0}", f3); // Field3 = c
    }
}

...

Важно: чтобы получить информацию о внутренних переменных и методах класса, эти переменные и методы должны быть общедоступными, то есть, объявлены с модификатором доступа public. В противном случае, скрытые внутренние переменные и скрытые методы есть невидимыми.

 

11. Каким образом получить информацию о типе с помощью System.Type.GetType()? Примеры

Типом может быть класс, интерфейс, структура, перечисление, делегат. Информация о типе (классе, интерфейсе, структуре и т.д.) получается с помощью статического метода GetType() класса System.Type. Метод GetType() получает входным параметром строку типа System.String. Эта строка должна содержать имя сборки и имя типа (класса, интерфейса, …) о котором нужно определить информацию.

Пример 1. Задана сборка с именем MyAssembly. В сборке объявлен класс с именем MyClass. Тогда строка, которая возвращает класс, который будет реализовывать сборку имеет следующий вид

...

System.Type T = GetType("MyAssembly.MyClass");

...

После этого, экземпляр (объект) T будет содержать информацию о классе MyClass.

Пример 2. Демонстрируется использование System.Type.GetType() для доступа к классу MathFunctions, описанного в п. 9. В данном примере предполагается, что класс MathFunctions объявляется внутри пространства имен TrainReflections1. Программный код всего модуля, который демонстрирует использование класса для консольного приложения следующий:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

// подключить пространство имен System.Reflection
using System.Reflection;

namespace TrainReflection1
{
    class MathFunctions
    {
        public int a, b, c; // члены данных класса

        // минимум между двумя значениями
        public int Min2(int a, int b)
        {
            if (a < b) return a;
            return b;
        }

        // минимум между тремя значениями
        public int Min3(int a, int b, int c)
        {
            int min = a;
            if (min > b) min = b;
            if (min > c) min = c;
            return min;
        }

        // максимум между двумя значениями
        public int Max2(int a, int b)
        {
            if (a < b) return b;
            return a;
        }
}

    class Program
    {
        static void Main(string[] args)
        {
            // получить значение типа
            Type tp = null;
            tp = Type.GetType("TrainReflection1.MathFunctions");

            // взять перечень методов из класса MathFunctions
            MethodInfo[] mi = tp.GetMethods();

            // получить названия методов
            string m1 = mi[0].Name; // m1 = "Min2"
            string m2 = mi[1].Name; // m2 = "Min3"
            string m3 = mi[2].Name; // m3 = "Max2"

            // взять перечень внутренних данных класса
            FieldInfo[] fi = tp.GetFields();

            string f1 = fi[0].Name; // f1 = "a"
            string f2 = fi[1].Name; // f2 = "b"
            string f3 = fi[2].Name; // f3 = "c"

            Console.WriteLine("Method1 = {0}", m1); // Method1 = Min2
            Console.WriteLine("Method2 = {0}", m2); // Method2 = Min3
            Console.WriteLine("Method3 = {0}", m3); // Method3 = Max2
            Console.WriteLine("Field1 = {0}", f1); // Field1 = a
            Console.WriteLine("Field2 = {0}", f2); // Field2 = b
            Console.WriteLine("Field3 = {0}", f3); // Field3 = c
        }
    }
}

 


Связанные темы