0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# で別のクラス・関数を文字列から呼び出す

Last updated at Posted at 2024-08-23

はじめに

プログラムを書いているだけだと特殊ケースではあるが、やはり特にスクリプト処理をパイプラインとして用意している場合などは、ダイナミックに関数の設定・呼び出しを行えると嬉しい。
特にその場合の呼び出し設定は文字列の場合も多い。

では、C# の場合、どうやって呼び出すのか?というのが気になった。

実行環境

  • Windows 11

実コード

呼び出し先

実行として呼び出し対対象のコードを簡単に用意しておく。

public class CallFunctions
{
    // Start is called before the first frame update
    public void SayHello()
    {
        Debug.Log("Hello, World!");
    }
}

呼び出し元

public class Call
{
    public static void CallFunction()
    {
        Type callFunc = Type.GetType("CallFunctions");
        ConstructorInfo callFuncConstructor = callFunc.GetConstructor(Type.EmptyTypes);
        object callFuncClassObject = callFuncConstructor.Invoke(new object[] { });

        MethodInfo sayHelloMethod = callFunc.GetMethod("SayHello");
        object callValeu = sayHelloMethod.Invoke(callFuncClassObject, new object[] { });
    }
}

順序としては、

  1. Type 型を使って、クラスオブジェクトを Type.GetType(<クラス名>) として呼びだす
  2. コンストラクタを取得する
  3. コンストラクタを呼び出す
  4. メソッド情報を取得する
  5. メソッドを呼び出す

といった流れ。
特にここでの重要なポイントはコンストラクタの呼び出しを忘れないこと。
これを忘れると、

error CS0103: The name 'callFuncClassObject' does not exist in the current context

としてエラーが返ってきてしまう。

ネームスペース下でのアクセス

例えば、 namespace Sample {} 下に呼び出し先があるとする。
この場合は、 Type.GetType({ClassName}) の ClassName 側を {Namespace}.{ClassName} として渡す必要がある。

呼び出し先

+ namespace Sample {
    public class CallFunctions : MonoBehaviour
    {
        // Start is called before the first frame update
        public void SayHello()
        {
            Debug.Log("Hello, World!");
        }
    }
+ }

呼び出し元

public class Call
{
    public static void CallFunction()
    {
-       Type callFunc = Type.GetType("CallFunctions");
+       Type callFunc = Type.GetType("Sample.CallFunctions");
        ConstructorInfo callFuncConstructor = callFunc.GetConstructor(Type.EmptyTypes);
        object callFuncClassObject = callFuncConstructor.Invoke(new object[] { });

        MethodInfo sayHelloMethod = callFunc.GetMethod("SayHello");
        object callValeu = sayHelloMethod.Invoke(callFuncClassObject, new object[] { });
    }
}

別アセンブリからのアクセス

呼び出し元のコードが A アセンブリに存在し、かつ、呼び出し元が B アセンブリに存在する場合。
ここでは、 Type.GetType() に対して {Namespace}.{ClassName},{AssemblyName} (コンマと要素間のスペースはあってもなくても良い。) の文字列を渡す。

呼び出し先

Assembly: A
namespace Sample {
    public class CallFunctions : MonoBehaviour
    {
        // Start is called before the first frame update
        public void SayHello()
        {
            Debug.Log("Hello, World!");
        }
    }
}

呼び出し元

Assembly: B
public class Call
{
    public static void CallFunction()
    {
-       Type callFunc = Type.GetType("Sample.CallFunctions");
+       Type callFunc = Type.GetType("Sample.CallFunctions, B");
        ConstructorInfo callFuncConstructor = callFunc.GetConstructor(Type.EmptyTypes);
        object callFuncClassObject = callFuncConstructor.Invoke(new object[] { });

        MethodInfo sayHelloMethod = callFunc.GetMethod("SayHello");
        object callValeu = sayHelloMethod.Invoke(callFuncClassObject, new object[] { });
    }
}

最後に

ぐぐりながらも出てきた結果を試してみたが、以外とコンストラクタの呼び出しを忘れて、そのクラスオブジェクト見つからないよと言われて沼ることがあった。
ここら辺は一個のお作法として覚えたいところ。

参考資料

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?