実行時に.NETアセンブリをロードして、名前だけを知っている型をインスタンス化できますか?


178

プロジェクト内のアセンブリへの参照を追加せずに、DLL名とクラス名しか持っていない場合、実行時にオブジェクトをインスタンス化することはできますか?クラスはインターフェースを実装するので、クラスをインスタンス化したら、それをインターフェースにキャストします。

アセンブリ名:

library.dll

タイプ名:

Company.Project.Classname


編集:私はDLLの絶対パスを持ってAssembly.LoadFileいないので、動作しません。DLLは、アプリケーションルート、system32にあるか、GACに読み込まれている可能性があります。

回答:


221

はい。を使用Assembly.LoadFromしてアセンブリをメモリにロードしてから、を使用Activator.CreateInstanceして、好みのタイプのインスタンスを作成できます。まず、リフレクションを使用してタイプを調べる必要があります。以下に簡単な例を示します。

Assembly assembly = Assembly.LoadFrom("MyNice.dll");

Type type = assembly.GetType("MyType");

object instanceOfMyType = Activator.CreateInstance(type);

更新

アセンブリファイル名とタイプ名がある場合、を使用Activator.CreateInstance(assemblyName, typeName)して.NETタイプ解決にタイプを解決するよう要求できます。これをtry / catchでラップすると、失敗した場合に、検索されない可能性がある追加のアセンブリを具体的に格納できるディレクトリの検索を実行できます。これは、その時点で前述の方法を使用します。


2
私はdllの絶対パスを持っていないので、assemlby.LoadFileなどです。他のアイデアは機能しませんか?
メガバイト

@rpいつでもお役に立てて嬉しいです(そして、そう言って1年しか遅れていません!)
Jeff Yates

2
@MegaByte:LoadFromはLoadFileとは異なります。依存関係が解決され、既知のパス(GAC、exeディレクトリなど)からDLL名が解決されます。詳細については、MSDNを参照してください。
ジェフイェイツ

1
もう1つ...(私も)ええと、型名として "MyType"だけを指定することはできません。その後にNAMESPACEを付ける必要があります。したがって、これはより正確になりますType type = assembly.GetType("MyNamespace"+"."+"MyType");
。– Cipi

1
@Cipi:技術的には、型は完全な名前空間の名前です(名前空間の概念は言語の利便性です)。CLR内に名前空間のない型を使用することができます。私は、過度に単純化した例を提供しただけです。
ジェフイェイツ

36

さまざまLoad*な方法の制限を考慮してください。MSDNドキュメントから...

LoadFileは、LoadFromコンテキストにファイルをロードせず、LoadFromメソッドのようにロードパスを使用して依存関係解決しません

ロードコンテキストの詳細については、LoadFromドキュメントをご覧ください。


19

Activator.CreateInstanceが機能するはずです。

IFace object = (IFace)Activator.CreateInstance( "AssemblyName",
                                                "TypeName" )
                               .Unwrap();

注:タイプ名は完全修飾タイプでなければなりません。

例:

var aray = (IList)Activator.CreateInstance("mscorlib","System.Collections.ArrayList").Unwrap();
aray.Add(10);

foreach (object obj in aray)
{
    Console.WriteLine(obj);
}

1
これについての注意:TypeName完全に修飾されている必要があります。私はこれを次のように呼び出さなければなりませんでした:Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") そして、それはを返しますObjectHandle。インターフェースを使い始めるには、次のことを行う必要がありますObjectHandle.UnWrap()
Anthony Sottile

7

この質問といくつかの回答は非常に役に立ちましたが、パスの問題がありました。そのため、この回答は、binディレクトリのパスを見つけることでライブラリの読み込みをカバーします。

最初の解決策:

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFrom(assemblyPath);
Type T = assembly.GetType("Company.Project.Classname");
Company.Project.Classname instance = (Company.Project.Classname) Activator.CreateInstance(T);

第二の解決策

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFile(assemblyPath);
(Company.Project.Classname) instance = (Company.Project.Classname) assembly.CreateInstance("Company.Project.Classname");

次のように、インターフェースにも同じ原則を使用できます(クラスを作成しますが、インターフェースにキャストします)。

(Company.Project.Interfacename) instance = (Company.Project.Interfacename) assembly.CreateInstance("Company.Project.Classname");

この例はWebアプリケーション用ですが、デスクトップアプリケーションにも同様に使用できます。たとえば、パスのみが異なる方法で解決されます。

Path.GetDirectoryName(Application.ExecutablePath)

5

それは簡単です。

MSDNの例:

public static void Main()
{
    // Use the file name to load the assembly into the current
    // application domain.
    Assembly a = Assembly.Load("example");
    // Get the type to use.
    Type myType = a.GetType("Example");
    // Get the method to call.
    MethodInfo myMethod = myType.GetMethod("MethodA");
    // Create an instance.
    object obj = Activator.CreateInstance(myType);
    // Execute the method.
    myMethod.Invoke(obj, null);
}

ここに参照リンクがあります

https://msdn.microsoft.com/en-us/library/25y1ya39.aspx


これは、コードの動的ロードをサポートするための恐ろしい方法です。MSは常に、あまりにも多くの詳細情報を取得することを強制することを好みました。
18

3

Framework v4.5以降では、Activator.CreateInstanceFrom()を使用して、アセンブリ内でクラスを簡単にインスタンス化できます。次の例は、それを使用する方法と、パラメーターを渡して戻り値を取得するメソッドを呼び出す方法を示しています。

    // Assuming moduleFileName contains full or valid relative path to assembly    
    var moduleInstance = Activator.CreateInstanceFrom(moduleFileName, "MyNamespace.MyClass");
    MethodInfo mi = moduleInstance.Unwrap().GetType().GetMethod("MyMethod");
    // Assuming the method returns a boolean and accepts a single string parameter
    bool rc = Convert.ToBoolean(mi.Invoke(moduleInstance.Unwrap(), new object[] { "MyParamValue" } ));


2
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();

2

* Assembly.Load **メソッドを使用してアセンブリをロードできます。Activator.CreateInstanceを使用すると、必要なタイプの新しいインスタンスを作成できます。ロードするクラスの完全な型名を使用する必要があることに注意してください(たとえば、Namespace.SubNamespace.ClassName)。TypeクラスのメソッドInvokeMemberを使用して、型のメソッドを呼び出すことができます。

また、一度読み込まれると、AppDomain全体がアンロードされるまでアセンブリをアンロードできないことも考慮してください(これは基本的にメモリリークです)。


2

この種の機能がプロジェクトにどの程度固有であるかに応じて、コンポーネントの読み込みと結合を処理するMEFのようなものを検討することをお勧めします。


2
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");

Type type = assembly.GetType("MyType");

dynamic instanceOfMyType = Activator.CreateInstance(type);

したがって、このようにして、methodinfoを取得せずに関数を使用してから、それを呼び出すことができます。このinstanceOfMyType.MethodName();のようにします。ただし、動的型はコンパイル時ではなく実行時に入力されるため、Intellisenseを使用することはできません。


1

はい、そうです。Assemblyクラスで静的なLoadメソッドを使用してから、Loadの呼び出しから返されたAssemblyインスタンスでCreateInstanceメソッドを呼び出して呼び出します。

また、必要に応じて、Assemblyクラスの「Load」で始まる他の静的メソッドの1つを呼び出すことができます。


0

あなたはこの方法でこれを行うことができます:

using System.Reflection;

Assembly MyDALL = Assembly.Load("DALL"); //DALL name of your assembly
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // name of your class
 object  obj = Activator.CreateInstance(MyLoadClass);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.