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


Study / C#    作成日付 : 2021/10/13 18:34:13   修正日付 : 2021/10/13 18:34:13

こんにちは。明月です。


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


Reflection機能とはインスタンスを動的で割り当てするか関数やフィールドおよび属性を動的に呼び出せる機能だという説明になっています。

link - https://docs.microsoft.com/

この説明は難しいですね。インスタンスを動的で割り当てするというのは我々がクラスのインスタンスを生成する時には普通はnewというキーワードを使います。

using System;

namespace Example
{
  // 例クラス
  class Node
  {
    // プロパティ
    public int Data { get; set; }
    // コンソールに出力する関数
    public void Print()
    {
      // コンソールに出力
      Console.WriteLine(Data);
    }
  }
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // インスタンス生成
      Node node = new Node();
      // プロパティにデータを入力
      node.Data = 10;
      // コンソールに出力する関数を呼び出す。
      node.Print();
      // 任意のキーを押してください
      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}


クラスのインスタンスは基本的にnewを利用して生成するというのは、以前に十分に説明しました。

link - [C#] 11. インスタンスう生成(new)とメモリ割り当て(StackメモリとHeapメモリ)そしてヌル(null)


インスタンスを生成する時、ソースにnew Nodeという作成します。Reflectionにはこれを静的の表現と言います。

つまり、データや分岐により他のインスタンスを生成したいならifを使ってソースを作成しなければならないです。

using System;

namespace Example
{
  // インターフェース
  interface INode
  {
    // 抽象関数
    void Print();
  }
  // 例クラス
  class Node1 : INode
  {    
    // コンソールに出力する関数
    public void Print()
    {
      // コンソールに出力
      Console.WriteLine("Node1");
    }
  }
  // 例クラス
  class Node2 : INode
  {
    // コンソールに出力する関数
    public void Print()
    {
      // コンソールに出力
      Console.WriteLine("Node2");
    }
  }
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // 任意のデータ
      string input = "Node1";
      // インスタンス生成
      INode node;
      // 任意のデータにより分岐
      if ("Node1".Equals(input))
      {
        // Node1クラスのインスタンス生成
        node = new Node1();
      }
      else
      {
        // Node2クラスのインスタンス生成
        node = new Node2();
      }
      // コンソールに出力する関数を呼び出す。
      node.Print();
      // 任意のキーを押してください
      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}


上の例をみればtypeという任意のデータを置いてNode1ならNode1のインスタンスを生成してその以外にはNode2のインスタンスを生成します。

でも、ここで仕様によりNode3のクラスが生成したら? ifを分岐してインスタンス生成する区間を作ることになります。もちろん、クラスをもっと生成するとMain関数がずっと修正が必要になります。

using System;

namespace Example
{
  // インターフェース
  interface INode
  {
    // 抽象関数
    void Print();
  }
  // 例クラス
  class Node1 : INode
  {
    // コンソールに出力する関数
    public void Print()
    {
      // コンソールに出力
      Console.WriteLine("Node1");
    }
  }
  // 例クラス
  class Node2 : INode
  {
    // コンソールに出力する関数
    public void Print()
    {
      // コンソールに出力
      Console.WriteLine("Node2");
    }
  }
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // Node2のTypeを取得
      Type type = Type.GetType("Example.Node2");
      // インスタンス生成
      INode node = (INode)Activator.CreateInstance(type);
      // コンソールに出力する関数を呼び出す。
      node.Print();
      // 任意のキーを押してください
      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}


このように作成するとクラスが生成してもType.GetTypeのString値によりインスタンス生成します。


また、我々がクラスのコンストラクタをprivateで生成することができます。

コンストラクタをprivateで設定をすればnewでインスタンスを生成することができません。コンストラクタが内部だけ生成することに設定したからです。代表的にシングルトンパターンがあります。

link - [Design pattern] 1-1. シングルトンパターン(Singleton pattern)


でも、Reflectionを使ったらコンストラクタをprivateに設定されてもインスタンス生成が可能です。

using System;
using System.Reflection;
using System.Linq;

namespace Example
{
  // 例クラス
  class Node
  {
    // コンストラクタをprivateに設定
    private Node()
    {

    }
    // コンソールに出力する関数
    public void Print()
    {
      // コンソールに出力
      Console.WriteLine("Node");
    }
  }
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // Node2のTypeを取得
      Type type = Type.GetType("Example.Node");
      // コンストラクタを取得
      var constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetParameters().Length == 0).First();
      // インスタンスを生成
      dynamic node = constructor.Invoke(null);
      // コンソールに出力する関数を呼び出す。
      node.Print();
      // 任意のキーを押してください
      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}


GetParameters関数を使ってコンストラクタの種類を取得してLinqのwhereでパラメータがないコンストラクタを一つ取得します。取得すればInvoke関数を使ってインスタンスを生成します。

つまり、パラメータがあるコンストラクタはLinqのWhereによりパラメータの個数やタイプで取得することができるし生成も可能です。


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


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

最新投稿