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

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


Зміст



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 . . .

 


Зв’язані теми