[C#] 53. Reflection機能を使い方 - Propertyとevent


Study / C#    作成日付 : 2021/10/19 21:02:58   修正日付 : 2021/10/19 21:02:58

こんにちは。明月です。


この投稿はC#でReflection機能を使い方 - Propertyとeventに関する説明です。


以前の投稿までC#のReflectionのClassとMethod、Variable(変数)に関して説明しました。

link - [C#] 50. Reflection機能を使い方 - Class

link - [C#] 51. Reflection機能を使い方 - Method

link - [C#] 52. Reflection機能を使い方 - Variable


Reflectionはクラスの構成要素に関して動的にデータを取得及び呼び出す方法です。

JavaにはClassの構成要素が関数とメンバー変数しかないですが、C#の場合はプロパティやイベントなどの特殊機能(?)をもっている関数があります。

プロパティは関数機能と変数の機能を合わせた要素だし、イベントは関数を複数で重畳して呼び出す機能です。

link - [C#] 21. C#のプロパティ(Property)

link - [C#] 25. イベント(event)キーワードを使い方


まず、プロパティのReflectionは関数のReflectionと似ています。

using System;
using System.Reflection;

namespace Example
{
  // 例クラス
  class Node
  {
    // メンバー変数
    private int data;
    // プロパティ
    public int Data
    {
      // set関数
      set
      {
        // コンソール出力
        Console.WriteLine("Data property set");
        // メンバー変数に値を入力
        this.data = value;
      }
      // set関数
      get
      {
        // コンソール出力
        Console.WriteLine("Data property get");
        // メンバー変数の値をリターン
        return this.data;
      }
    }
  }
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // インスタンス生成
      var node = new Node();
      // Nodeクラスのtypeを取得
      Type type = typeof(Node);
      // プロパティのDataのReflection情報を取得
      PropertyInfo property = type.GetProperty("Data");
      // Dataプロパティのset関数を呼び出す、値の10を入力
      property.SetValue(node, 10);
      // Dataプロパティのget関数を呼び出して値を取得
      var value = property.GetValue(node);
      // コンソール出力
      Console.WriteLine(value);

      // 任意のキーを押してください
      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}


上の例はNodeクラスのDataプロパティのset関数とget関数を呼び出すReflectionです。

プロパティがOOPの規約のためにget、set関数なので、関数のReflectionと差異がありません。プロパティもprivateを設定することができるし、staticで設定することができますが、普通はpublicで設定します。でも、publicではなくても関数のReflectionみたいにBindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Staticのオプションで取得することができます。


eventの場合は関数を重畳して一括で呼び出す方法です。

using System;
using System.Reflection;

namespace Example
{
  // 例クラス
  class Node
  {
    // デリゲート
    public event EventHandler ExecuteEvent;
  }
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // インスタンス生成
      Node node = new Node();
      // Nodeクラスのtypeを取得
      Type type = typeof(Node);
      // ExecuteEventのEvent reflectionを取得
      EventInfo eventInfo = type.GetEvent("ExecuteEvent");
      // イベントに追加する関数
      MethodInfo methodInfo = typeof(Program).GetMethod("Print_Event", BindingFlags.NonPublic | BindingFlags.Static);
      // 関数をDelegateで変換
      Delegate d = Delegate.CreateDelegate(eventInfo.EventHandlerType, null, methodInfo);
      // イベント追加
      eventInfo.AddEventHandler(node, d);
      // イベント追加
      eventInfo.AddEventHandler(node, d);
      // イベント追加
      eventInfo.AddEventHandler(node, d);
      // ExecuteEventイベントに関する実行フィールドを取得
      var backingField = typeof(Node).GetField("ExecuteEvent", BindingFlags.Instance | BindingFlags.NonPublic);
      // nodeインスタンスからハンドラー取得
      var handler = (EventHandler)backingField.GetValue(node);
      // 実行
      handler("Execute", new EventArgs());

      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
    // コンソール出力するイベント関数
    static void Print_Event(object sender, EventArgs e)
    {
      // コンソール出力
      Console.WriteLine(sender);
    }
  }
}


上の例ではGetEvent関数を通ってNodeクラスのeventを取得します。

イベントにはDelegateタイプでイベントを追加しますが、Delegate.CreateDelegateを通って関数をデリゲート(関数ポインター)タイプに変換しなければならないです。

そしてevent reflectionを通ってイベントを追加します。私の場合は3回に追加しました。


実はイベントはクラス内部で実行しなければならないです。でも、そうなるとReflection機能ではないでしょう。外部でeventを呼び出すためには実行Fieldデータを取得しなければならないです。この部分が面白いことはここではeventをメンバー変数タイプで作成しましたが、メンバー変数で認識します。

eventのアクセス修飾子がpublicですが、privateで認識します。その方法でFieldを取得してEventHandlerのデリーケートタイプで強制キャストしたら関数みたいに呼び出すができます。


ここまでC#でReflection機能を使い方 - Propertyとeventに関する説明でした。


ご不明なところや間違いところがあればコメントしてください。

#C#
最新投稿