[c#] C #에서 런타임에 DLL로드

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();
        }
    }
}



답변

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();
        }
    }
}


답변

지금 은 어셈블리에 정의 된 모든 유형 의 인스턴스를 만들고 있습니다. Class1메서드를 호출하려면 의 단일 인스턴스 만 생성 하면됩니다.

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();
    }
}


답변

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();
     }


답변

Activator.CreateInstance() Output 메서드가없는 개체를 반환합니다.

동적 프로그래밍 언어에서 온 것 같습니까? C #은 분명히 그렇지 않으며, 당신이하려는 일은 어려울 것입니다.

특정 위치에서 특정 dll을로드하고 있으므로 콘솔 응용 프로그램에 대한 참조로 추가하고 싶습니까?

를 통해 어셈블리를로드하려면 Assembly.Load리플렉션을 통해 멤버를 호출해야합니다.c

같은 일 type.GetMethod("Output").Invoke(c, null);을해야합니다.


답변

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);
}

출력 : 340 0 0

따라서 경우에 대비하여 Reflection이 검색하기 전에 잠재적으로 해당 코드를 실행할 수 있습니다.


답변

그렇게 어렵지 않습니다.

로드 된 객체의 사용 가능한 기능을 검사 할 수 있으며, 이름으로 찾고있는 것을 찾으면 예상 매개 변수가 있으면 스누핑합니다. 찾으려는 호출 인 경우 MethodInfo 개체의 Invoke 메서드를 사용하여 호출하십시오.

또 다른 옵션은 단순히 외부 개체를 인터페이스에 빌드하고로드 된 개체를 해당 인터페이스로 캐스팅하는 것입니다. 성공하면 기본적으로 함수를 호출합니다.

이것은 매우 간단한 것입니다.


답변