2013-08-21 14 views
46

Próbuję ustalić, w jaki sposób można zaimportować i użyć pliku .dll w środowisku wykonawczym w aplikacji języka C#. Używam Assembly.LoadFile() Udało mi się dostać mój program do załadowania biblioteki DLL (ta część zdecydowanie działa, ponieważ jestem w stanie uzyskać nazwę klasy za pomocą ToString()), jednak nie jestem w stanie użyć "Output" metoda z poziomu mojej aplikacji konsoli. Kompiluję plik .dll, a następnie przenoszę go do projektu mojej konsoli. Czy istnieje dodatkowy krok między CreateInstance, a następnie możliwość korzystania z metod?Ładowanie bibliotek DLL w środowisku wykonawczym w języku C#

Jest to klasa w moim DLL:

namespace DLL 
{ 
    using System; 

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

i tutaj jest zastosowanie chcę, aby załadować biblioteki 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(); 
     } 
    } 
} 
+0

http: // stackoverflow.com/questions/2202381/reflection-how-to-invoke-method-with-parameters – Stu

Odpowiedz

74

członków musi być rozpoznawana w czasie kompilacji być wywoływane bezpośrednio z C# . W przeciwnym razie musisz użyć obiektów odbijających lub dynamicznych.

Odbicie

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

Dynamiczny (.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(); 
     } 
    } 
} 
+5

Zauważ, że to próbuje wywołać 'Output' na każdym typie w zespole, który prawdopodobnie wyrzuci zanim znajdzie się" właściwa "klasa. –

+1

@ReedCopsey, Zgoda, ale dla jego prostego przykładu, jego typ jest jedyny widoczny. "Jedynymi typami widocznymi poza złożeniem są typy publiczne i typy publiczne zagnieżdżone w innych typach publicznych." Dla nietrywialnego przykładu, oczywiście będzie to problem ... –

+1

Schludny z dwoma przykładami! :) –

25

Teraz tworzysz instancję każdy typ zdefiniowany w zespole. Wystarczy tylko utworzyć pojedynczą instancję Class1 w celu wywołania metody:

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

Musisz utworzyć wystąpienie typu, które narażają metody 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(); 
    } 
+0

Dziękuję bardzo - właśnie tego szukam. Nie mogę uwierzyć, że to nie jest wyższa ocena niż inne odpowiedzi, ponieważ pokazuje użycie słowa kluczowego dynamicznego. – skiphoppy

+0

Ah, teraz widzę, że to też było w odpowiedzi DarkFalcon. Twoja była krótsza i łatwiejsza do zobaczenia. :) – skiphoppy

0

Activator.CreateInstance() zwraca obiekt , który nie ma metody Output.

Wygląda na to, że pochodzisz z dynamicznych języków programowania? C# to zdecydowanie nie to, a to, co próbujesz zrobić, będzie trudne.

Ponieważ ładujesz określoną bibliotekę dll z określonej lokalizacji, może po prostu chcesz dodać ją jako odniesienie do aplikacji konsoli?

Jeśli koniecznie chcesz załadować montaż poprzez Assembly.Load, trzeba będzie pójść za pośrednictwem refleksji zadzwonić żadnych członków na c

coś takiego type.GetMethod("Output").Invoke(c, null); powinno wystarczyć.

-4

To nie jest takie trudne.

Można sprawdzić dostępne funkcje załadowanego obiektu, a jeśli znajduje się poszukiwany przez nazwę, a następnie śledź oczekiwane parms, jeśli takie istnieją. Jeśli jest to połączenie, które próbujesz znaleźć, a następnie wywołaj je za pomocą metody Invoke obiektu MethodInfo.

Inną opcją jest proste zbudowanie zewnętrznych obiektów do interfejsu i przesłanie załadowanego obiektu do tego interfejsu. Jeśli się powiedzie, wywołaj funkcję natywnie.

To dość proste rzeczy.

+0

Wow, nie jestem pewien, dlaczego głosy na dół. Mam aplikację produkcyjną robiącą to dokładnie tak jak w ciągu ostatnich 12 lat. * wzruszenie ramion * Każdy potrzebuje kodu, żeby to zrobić, zrób mi wiadomość. Spakuję fragmenty kodu produkcyjnego i wyślę go dalej. – ChrisH

Powiązane problemy