C #에서 런타임에 DLL로드


91

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

답변:


128

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

12
이것은 Output"올바른"클래스가 발견되기 전에 던질 가능성이있는 어셈블리의 모든 유형 을 호출하려고 시도합니다 .
Reed Copsey

1
@ReedCopsey, 동의하지만 그의 간단한 예를 들어 그의 유형은 유일한 유형입니다. "어셈블리 외부에서 볼 수있는 유일한 형식은 공용 형식과 다른 공용 형식 내에 중첩 된 공용 형식입니다." 사소하지 않은 예를 들어, 분명히 이것은 문제가 될 것입니다 ...
Dark Falcon

1
두 가지 예를 들어 깔끔하게! :)
닐스 Abildgaard

22
이것이 인터페이스가 자주 사용되는 이유 IDog dog = someInstance as IDog;이며 null이 아닌지 테스트하는 등의 기능 감지를 수행 할 수 있습니다 . 클라이언트가 공유하는 공용 DLL에 인터페이스를 넣으면 동적으로로드 될 모든 플러그인이 해당 인터페이스를 구현해야합니다. 그러면 IDog 인터페이스에 대해 클라이언트를 코딩하고 동적을 사용하는 대신 컴파일 타임에 intellisense + strong 유형 검사를 수행 할 수 있습니다.
AaronLS 2014

1
@ Tarek.Mh : .NET Framework에 대한 컴파일 타임 종속성이 필요합니다 Class1. 이 시점에서 new Class1(). asker는 런타임 종속성을 명시 적으로 지정했습니다. dynamic프로그램이 컴파일 시간에 대한 종속성을 전혀 요구하지 않도록합니다 Class1.
Dark Falcon

39

지금 은 어셈블리에 정의 된 모든 유형 의 인스턴스를 만들고 있습니다. 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();
    }
}

19

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

정말 감사합니다-이것이 제가 찾고있는 것입니다. 동적 키워드의 사용을 보여주기 때문에 이것이 다른 답변보다 높은 등급이 아니라는 것을 믿을 수 없습니다.
skiphoppy

아, 이제 DarkFalcon의 답변에도 포함되어 있습니다. 당신의 것은 더 짧았고보기 쉽게 만들었습니다. :)
skiphoppy

0

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

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

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

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

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


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

출력 : 340 0 0

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


-1

그렇게 어렵지 않습니다.

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

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

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


왜 반대표를 던 졌는지 모르겠네요. 지난 12 년 동안 정확히이 작업을 수행하는 프로덕션 애플리케이션이 있습니다. * 어깨를 으쓱 * 누구나이 작업을 수행하려면 코드가 필요합니다. 메시지를 쏘세요. 프로덕션 코드의 일부를 패키징하여 함께 보낼 것입니다.
ChrisH

10
나는 반대표가 예제의 부족과 압축 된 어조와 관련이있을 것이라고 생각합니다 ... 당신은 완전한 답변에 대한 근거를 가지고있는 것 같으니 더 자세한 내용을 편집하는 것을 두려워하지 마십시오 :)
Shadow

1
"이것은 매우 간단한 일입니다"라고 말하는 것은 일종의 무례한 일이며, 그것이 당신이 반대표를 얻은 이유입니다.
ABPerson

1
나는 무례하거나 굴욕적이지 않았다 .... 6 년 전. 톤은 텍스트에서 명확하게 나오지 않습니다. 그것은 정말도 ... 마음 꽤 빛을 의미했다 정말 내가 거기에 모든 년에서 코드 샘플에 대한 링크를 가지고 같은 느낌, 그리고 내가 기억하는 것 같은 그것이 정말로이 가정 (가서 아무 생각이 없다 ). : \
ChrisH

MethodInfo가 어떻게 작동하는지 모르겠지만 가치있는 것 같습니다. 나는 당신의 대답이 현재 받아 들여지는 것보다 더 나을 가능성이 있다고 말하고 싶지만 완성되어야 할 것입니다. 주위를 둘러 보면 감사하겠습니다. 그렇다면 코드 샘플에 연결하지 마십시오. 이들은 미래에 깨질 수 있습니다. 계속해서 읽을 수 있도록 소스에 대한 링크 나 추가 정보와 함께 샘플을 직접 제공하는 것이 가장 좋습니다.
SpaghettiCook
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.