99

C# アプリケーション内で実行時に .dll をインポートして使用する方法を理解しようとしています。Assembly.LoadFile() を使用して、プログラムに dll をロードさせることができました (ToString() を使用してクラスの名前を取得できるため、この部分は確実に機能しています)。ただし、「出力」を使用することはできません。私のコンソールアプリケーション内からのメソッド。.dll をコンパイルしてから、コンソールのプロジェクトに移動しています。CreateInstance とメソッドを使用できるようになるまでに、追加の手順はありますか?

これは私のDLLのクラスです:

namespace DLL
{
    using System;

    public class Class1
    {
        public void Output(string s)
        {
            Console.WriteLine(s);
        }
    }
}

そして、ここにDLLをロードしたいアプリケーションがあります

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                var c = Activator.CreateInstance(type);
                c.Output(@"Hello");
            }

            Console.ReadLine();
        }
    }
}
4

6 に答える 6

137

メンバーは、C# から直接呼び出されるようにコンパイル時に解決可能である必要があります。それ以外の場合は、リフレクションまたは動的オブジェクトを使用する必要があります。

反射

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                var c = Activator.CreateInstance(type);
                type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {@"Hello"});
            }

            Console.ReadLine();
        }
    }
}

動的 (.NET 4.0)

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                dynamic c = Activator.CreateInstance(type);
                c.Output(@"Hello");
            }

            Console.ReadLine();
        }
    }
}
于 2013-08-21T16:05:47.070 に答える
42

現在、アセンブリで定義されているすべての型のインスタンスを作成しています。Class1メソッドを呼び出すには、 のインスタンスを 1 つだけ作成する必要があります。

class Program
{
    static void Main(string[] args)
    {
        var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

        var theType = DLL.GetType("DLL.Class1");
        var c = Activator.CreateInstance(theType);
        var method = theType.GetMethod("Output");
        method.Invoke(c, new object[]{@"Hello"});

        Console.ReadLine();
    }
}
于 2013-08-21T16:08:19.527 に答える
21

Outputメソッドを公開する型のインスタンスを作成する必要があります。

static void Main(string[] args)
    {
        var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

        var class1Type = DLL.GetType("DLL.Class1");

        //Now you can use reflection or dynamic to call the method. I will show you the dynamic way

        dynamic c = Activator.CreateInstance(class1Type);
        c.Output(@"Hello");

        Console.ReadLine();
     }
于 2013-08-21T16:11:52.790 に答える
0

Activator.CreateInstance()Output メソッドを持たないオブジェクトを返します。

あなたは動的プログラミング言語から来ているように見えますか? C# は明らかにそうではなく、やろうとしていることは難しいでしょう。

特定の場所から特定の dll をロードしているので、それをコンソール アプリケーションへの参照として追加したいだけでしょうか?

絶対に 経由でアセンブリをロードしたい場合はAssembly.Load、リフレクション経由でメンバーを呼び出す必要があります。c

のような何かtype.GetMethod("Output").Invoke(c, null);がそれを行う必要があります。

于 2013-08-21T16:13:26.447 に答える
0
foreach (var f in Directory.GetFiles(".", "*.dll"))
            Assembly.LoadFrom(f);

これにより、実行可能ファイルのフォルダーにあるすべての DLL が読み込まれます。

私の場合Reflection、他のDLLであっても、クラスのすべてのサブクラスを見つけるために使用しようとしていました。これはうまくいきましたが、それが最善の方法であるかどうかはわかりません。

編集:私はそれを計りました、そしてそれはそれらを最初にロードするようです.

Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 4; i++)
{
    stopwatch.Restart();
    foreach (var f in Directory.GetFiles(".", "*.dll"))
        Assembly.LoadFrom(f);
    stopwatch.Stop();
    Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

出力: 34 0 0 0

そのため、念のため、Reflection が検索する前にそのコードを実行する可能性があります。

于 2020-11-05T06:24:50.580 に答える
-1

それほど難しくありません。

ロードされたオブジェクトの利用可能な関数を調べることができます。名前で探している関数が見つかった場合は、予想されるパラメーターがあればそれをスヌープします。探している呼び出しである場合は、MethodInfo オブジェクトの Invoke メソッドを使用して呼び出します。

もう 1 つのオプションは、単に外部オブジェクトをインターフェイスに構築し、読み込まれたオブジェクトをそのインターフェイスにキャストすることです。成功した場合は、関数をネイティブに呼び出します。

これはかなり単純なことです。

于 2014-10-06T14:29:20.880 に答える