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

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


Содержание


1. Что собой представляет метод System.Type.GetType()?

Метод System.Type.GetType() предназначен для получения экземпляра типа, который задан параметром. Параметр метода есть тип string. Параметр указывает название типа, для которого нужно получить информацию. В общем случае, метод System.Type.GetType() имеет 7 перегруженных реализаций.

Чтобы получить перечень методов некоторого типа (например, класса) нужно сначала получить объект, содержащий информацию о типе. Это делается с помощью метода

GetType("NameSpace.TypeName")

где

  • NameSpace – название пространства имен, в котором размещается тип с именем TypeName, требующий исследования;
  • TypeName – название типа, о котором нужно получить информацию. Типом может быть класс, структура, интерфейс, перечисление, делегат.

Например

Type tp = Type.GetType("Dates.Date");

В этом примере нужно создается экземпляр (объект) с именем tp, содержащий информацию о типе с именем Date, который объявлен в пространстве имен Dates.

 

2. Что такое рефлексия методов? Как получить информацию о методах? Пример рефлексии методов

Рефлексия методов позволяет получить информацию о перечне общедоступных (public) методов из заданного типа. Информацию о методах можно получать для класса, структуры или интерфейса. Только эти типы могут содержать объявления методов.
Чтобы получить перечень методов заданного экземпляра типа, нужно вызвать метод GetMethods(), возвращающий массив типа MethodInfo, который содержит всю необходимую информацию о методах.

Пример. Задан класс Date, который описывает дату. В классе реализованы 3 внутренние переменные и 6 методов доступа к ним. Ниже приведен текст программы, которая демонстрирует рефлексию методов. Программа создана по шаблону Console Application.

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

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

namespace ConsoleApp2
{
  // класс, который описывает дату
  public class Date
  {
    int number;
    int month;
    int year;

    //
    public int GetNumber() { return number; }
    public int GetMonth() { return month; }
    public int GetYear() { return year; }

    public void SetNumber(int nnumber) { number = nnumber; }
    public void SetMonth(int nmonth) { month = nmonth; }
    public void SetYear(int nyear) { year = nyear; }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // получить информацию о методах
      // получить экземпляр типа по его имени
      Type tp = Type.GetType("ConsoleApp2.Date"); // название класса - "Date" в сборке ConsoleApp2

      // получить массив методов класса Date
      MethodInfo[] methods = tp.GetMethods();

      // вывести названия методов на экран
      int i = 0;
      foreach (MethodInfo mi in methods)
      {
        i++;
        Console.WriteLine("Method[{0}] = {1}", i, mi.Name);
      }
    }
  }
}

В результате выполнения данного кода, на экран будет выведен перечень названий методов, которые доступны для любого объекта класса Date:

Method[1] = GetNumber
Method[2] = GetMonth
Method[3] = GetYear
Method[4] = SetNumber
Method[5] = SetMonth
Method[6] = SetYear
Method[7] = ToString
Method[8] = Equals
Method[9] = GetHashCode
Method[10] = GetType
Press any key to continue . . .

Следует отметить следующее:

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

 

3. Как получить информацию о полях класса, структуры или перечисления? Примеры рефлексии полей и свойств

Чтобы получить информацию о поле (свойстве) некоторого типа (класс, структура, перечисление), нужно использовать метод Type.GetFields(). Этот метод возвращает массив типа FieldInfo. Тип FieldInfo содержит всю необходимую информацию о полях и свойствах, которые объявлены как public.

Пример 1. Получение информации о полях структуры. Задана структура Worker. В структуре реализованы 3 поля с именами name, age, rank. В примере демонстрируется вывод информации о названии поля и его типе (свойство FieldType). Пример реализован как консольное приложение

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

// подключить System.Reflection
using System.Reflection;

namespace TrainReflection
{
  // структура, которая реализует информацию о работнике
  public struct Worker
  {
    public static string name; // имя работника
    public int age; // век работника
    public float rank; // рейтинг работника
  }

  class Program
  {
    static void Main(string[] args)
    {
      // получить информацию о полях структуры Worker
      // создать объект, который содержит информацию о структуре Worker
      Type tp = Type.GetType("TrainReflection.Worker");

      // получить информацию о полях структуры Worker
      FieldInfo[] fields = tp.GetFields();

      // вывести названия полей, их типы и некоторые атрибуты
      int i = 0;
      string nameType;
      foreach (var field in fields)
      {
        i++;
        nameType = field.FieldType.ToString(); // получить название типа поля field структуры Worker
        Console.Write("Field[{0}] = {1}, type = {2}", i, field.Name, nameType);

        // проверка, статическое ли это поле
        if (field.IsStatic) Console.Write(", static");

        // проверка, объявлено ли поле как public
        if (field.IsPublic) Console.Write(", public");
        Console.WriteLine();
      }
    }
  }
}

В результате, на экран будет выведен следующий текст:

Field[1] = age, type = System.Int32, public
Field[2] = rank, type = System.Single, public
Field[3] = name, type = System.String, static, public
Press any key to continue . . .

Таким же образом можно получить информацию о полях любого класса любой сборки. Достаточно знать только имя класса в сборке.

Пример 2. Получение информации о полях перечисления. Задано перечисление Month, реализующее сокращенные названия месяцев года. Ниже приведен пример получения информации о перечислении на основе информации о его имени.

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

// подключить System.Reflection
using System.Reflection;

namespace TrainReflection
{
  // перечисление, реализующее информацию о месяце года
  enum Month
  {
    Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
  }

  class Program
  {
    static void Main(string[] args)
    {
      // получить информацию о полях перечисления Month

      // создать объект, который содержит информацию о структуре Worker
      Type tp = Type.GetType("TrainReflection.Month");

      // получить информацию о полях перечисления Month
      FieldInfo[] fields = tp.GetFields();

      // вывести названия полей перечисления enum
      int i = 0;
      string value;
      foreach (var field in fields)
      {
        i++;
        Console.WriteLine("Field[{0}] = {1}", i, field.Name);
      }
    }
  }
}

В результате, на экран будет выведен следующий текст

Field[1] = value__
Field[2] = Jan
Field[3] = Feb
Field[4] = Mar
Field[5] = Apr
Field[6] = May
Field[7] = Jun
Field[8] = Jul
Field[9] = Aug
Field[10] = Sep
Field[11] = Oct
Field[12] = Nov
Field[13] = Dec
Press any key to continue . . .

 

4. Как получить информацию об интерфейсах, которые реализует класс? Пример рефлексии интерфейсов

Чтобы получить перечень имен интерфейсов, которые поддерживаются заданным типом, используется метод GetInterfaces(). Этот метод возвращает массив интерфейсов типа Type[].
Название интерфейса помещается в свойстве Name.



Пример. Пусть задан интерфейс IDate, в котором объявляются имена двух методов: GetNumber(), SetNumber(). Также объявляется класс Date, реализующий дату. Класс Date наследует интерфейс IDate. В примере продемонстрировано:

  • получение списка интерфейсов класса Date;
  • получение списка методов интерфейса IDate.

Полный листинг программы, которая демонстрирует данный пример

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

// подключить System.Reflection
using System.Reflection;

namespace TrainReflection
{
  // интерфейс с двумя объявленными методами
  interface IDate
  {
    int GetNumber();
    void SetNumber(int nnumber);
  }

  // класс, который описывает дату - наследует интерфейс IDate
  public class Date:IDate
  {
    int number;
    int month;
    int year;

    //
    public int GetNumber() { return number; }
    public int GetMonth() { return month; }
    public int GetYear() { return year; }

    public void SetNumber(int nnumber) { number = nnumber; }
    public void SetMonth(int nmonth) { month = nmonth; }
    public void SetYear(int nyear) { year = nyear; }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // получить информацию о методах
      // получить экземпляр типа по его имени
      Type tp = Type.GetType("TrainReflection.Date"); // название класса - "Date"

      // получить массив интерфейсов класса Date
      Type[] interfaces = tp.GetInterfaces();

      // вывести названия интерфейсов класса Date на экран
      int i = 0;
      foreach (Type t in interfaces)
      {
        i++;
        Console.WriteLine("Interface[{0}] = {1}", i, t.Name);
      }

      Console.WriteLine();

      // создать объект, который содержит информацию об интерфейсе IDate
      Type tpi = Type.GetType("TrainReflection.IDate");

      // получить массив методов для интерфейса IDate с помощью объекта tpi
      MethodInfo[] methods = tpi.GetMethods();

      // вывести перечень методов интерфейса IDate
      i = 0;
      foreach (MethodInfo mt in methods)
      {
        i++;

        // вывести полное имя каждого метода интерфейса
        Console.WriteLine("Method[{0}] = {1}", i, mt.Name);
      }
    }
  }
}

В результате выполнения программы на экран будет выведено:

Interface[1] = IDate

Method[1] = GetNumber
Method[2] = SetNumber
Press any key to continue . . .

 

5. Пример использования рефлексии для получения дополнительных сведений о типе (классе, структуре, перечислении)

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

Пример. Пусть заданы два класса:

  • класс Point, который реализует точку на координатной плоскости;
  • класс Pixel, который реализует точку заданного цвета. Класс Pixel унаследован от класса Point.

Ниже приводится полный текст программы, которая выводит дополнительные сведения о классах Point и Pixel. Программа реализована как приложение типа Console Application.

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

// подключить System.Reflection
using System.Reflection;

namespace TrainReflection
{
  public class Point
  {
    // внутренние переменные класса
    protected int x;
    protected int y;

    // методы доступа
    public void GetXY(out int xx, out int yy)
    {
      xx = x;
      yy = y;
    }

    public void SetXY(int xx, int yy)
    {
      x = xx;
      y = yy;
    }
  }

  // класс Pixel есть производным от класса Point
  sealed class Pixel:Point
  {
    // внутренняя переменная color
    int color;

    // методы доступа
    public void GetXYC(out int xx, out int yy, out int cl)
    {
      GetXY(out xx, out yy);
      cl = color;
    }

    public void SetXYC(int xx, int yy, int cl)
    {
      SetXY(xx, yy);
      color = cl;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // создать объекты для классов Point и Pixel
      Type tPoint = Type.GetType("TrainReflection.Point");
      Type tPixel = Type.GetType("TrainReflection.Pixel");

      // вывести некоторую информацию о классе Point
      Console.WriteLine("Information about Point class:");
      if (tPoint.IsAbstract) Console.WriteLine("Abstract class"); // абстрактный класс
      if (tPoint.IsArray) Console.WriteLine("Array"); // это есть массив
      if (tPoint.IsClass) Console.WriteLine("Class or delegate"); // это есть класс или делегат
      if (tPoint.IsEnum) Console.WriteLine("Enumeration"); // это есть перечисление
      if (tPoint.IsInterface) Console.WriteLine("Interface"); // это есть интерфейс
      if (tPoint.IsPublic) Console.WriteLine("Public"); // объявлен как public
      if (tPoint.IsSealed) Console.WriteLine("Sealed"); // запечатан

      Console.WriteLine();

      // вывести некоторую информацию о классе Pixel
      Console.WriteLine("Information about Pixel class:");
      if (tPixel.IsAbstract) Console.WriteLine("Abstract class"); // абстрактный класс
      if (tPixel.IsArray) Console.WriteLine("Array"); // это есть массив
      if (tPixel.IsClass) Console.WriteLine("Class or delegate"); // это есть класс или делегат
      if (tPixel.IsEnum) Console.WriteLine("Enumeration"); // это есть перечисление
      if (tPixel.IsInterface) Console.WriteLine("Interface"); // это есть интерфейс
      if (tPixel.IsPublic) Console.WriteLine("Public"); // объявлен как public
      if (tPixel.IsSealed) Console.WriteLine("Sealed"); // запечатан
    }
  }
}

В результате выполнения программы, на экран будет выведено следующее:

Information about Point class:
Class or delegate
Public

Information about Pixel class:
Class or delegate
Sealed
Press any key to continue . . .

 

6. Как получить информацию о свойствах (properties) класса? Пример

Чтобы получить информацию о свойствах класса нужно вызвать метод GetProperties(). Этот метод возвращает массив типа PropertyInfo[]. Массив PropertyInfo[] содержит сведения о свойствах (properties) класса.

Пример. Продемонстрировано получение перечня свойств для класса Student из пространства имен TrainReflection. Свойства обязательно должны быть объявлены с модификатором доступа public.

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

// подключить System.Reflection
using System.Reflection;

namespace TrainReflection
{
  // информация о студенте
  class Student
  {
    string name; // имя студента
    string numBook; // номер зачетной книжки
    float rank; // рейтинг студента

    // свойства
    public string Name
    {
      get { return name; }
      set { name = value; }
    }

    public string NumBook
    {
      get { return numBook; }
      set { numBook = value; }
    }

    public float Rank
    {
      get { return rank; }
      set { rank = value; }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // получить информацию о свойствах из класса Student
      // получить объект типа System.Type
      Type tp = Type.GetType("TrainReflection.Student");

      // получить перечень свойств
      PropertyInfo[] properties = tp.GetProperties();

      // вывести перечень свойств
      int i = 0;
      foreach (PropertyInfo p in properties)
      {
        i++;
        Console.WriteLine("Property[{0}] = {1}", i, p.Name);
      }
    }
  }
}

На экран будет выведен следующий текст

Property[1] = Name
Property[2] = NumBook
Property[3] = Rank
Press any key to continue . . .

 

7. Пример использования рефлексии для получения информации о параметрах метода

Для конкретного метода можно получить информацию о его параметрах.

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

// подключить System.Reflection
using System.Reflection;

namespace TrainReflection
{
  // класс, который содержит математические функции
  class MathFunctions
  {
    // метод, который решает квадратное уравнение
    public bool CalcEquation(double a, double b, double c, out double x1, out double x2)
    {
      double d = b * b - 4 * a * c;

      if (a==0)
      {
        if (b==0)
        {
          x1 = x2 = 0;
          return false;
        }
        else
        {
          x1 = x2 = -c / b;
          return true;
        }
      }

      if (d<0)
      {
        x1 = x2 = 0;
        return false;
      }

      x1 = (-b - Math.Sqrt(d)) / (2 * a);
      x2 = (-b + Math.Sqrt(d)) / (2 * a);

      return true;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // получить информацию о свойствах из класса Student

      // получить объект типа System.Type
      Type tp = Type.GetType("TrainReflection.MathFunctions");

      // получить объект, который содержит информацию о конкретном методе CalcEquation класса MathFunctions
      MethodInfo method = tp.GetMethod("CalcEquation");

      // получить параметры метода CalcEquation
      ParameterInfo[] parameters = method.GetParameters();

      // вывести параметры метода
      Console.WriteLine("Parameters of method CalcEquation:");

      int i = 0;
      foreach (ParameterInfo p in parameters)
      {
        i++;
        Console.WriteLine("Parameter[{0}] = {1} of type {2}", i, p.Name, p.ParameterType.Name);
      }

      // вывести тип значения, которое возвращается методом
      string returnType = method.ReturnType.FullName;

      Console.WriteLine();
      Console.WriteLine("The returned type: {0}", returnType);
    }
  }
}

Вывод на экран будет следующим

Parameters of method CalcEquation:
Parameter[1] = a of type Double
Parameter[2] = b of type Double
Parameter[3] = c of type Double
Parameter[4] = x1 of type Double&
Parameter[5] = x2 of type Double&

The returned type: System.Boolean
Press any key to continue . . .

 


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