2012-05-24 15 views
8

Ich habe ein Beispiel:Kann ich Activator.CreateInstance mit einer Schnittstelle verwenden?

 Assembly asm = Assembly.Load("ClassLibrary1"); 
     Type ob = asm.GetType("ClassLibrary1.UserControl1"); 
     UserControl uc = (UserControl)Activator.CreateInstance(ob); 
     grd.Children.Add(uc); 

Es eine Instanz einer Klasse Ich schaffe, aber wie kann ich eine Instanz einer Klasse zu erstellen, die eine gewisse Schnittstelle implementiert? d. h. UserControl1 implementiert ILoad Schnittstelle.

U: Ich kann Objekt später zu Schnittstelle umwandeln, aber ich weiß nicht, welcher Typ in den Baugruppen die Schnittstelle implementiert.

+6

Sie keine Instanz einer Schnittstelle schaffen; Sie können die Klasse erstellen, die die Schnittstelle implementiert, und sie als Schnittstelle übergeben. – Marco

+1

Sie können ein Objekt vom Typ ILoad nicht instanziieren, es ist eine Schnittstelle. – JustinDanielson

Antwort

14

Dies ist ein Code, den ich ein paar Mal verwendet habe. Es findet alle Typen in einer Assembly, die eine bestimmte Schnittstelle implementieren:

Type[] iLoadTypes = (from t in Assembly.Load("ClassLibrary1").GetExportedTypes() 
        where !t.IsInterface && !t.IsAbstract 
        where typeof(ILoad).IsAssignableFrom(t) 
        select t).ToArray(); 

Dann haben Sie alle Arten in ClassLibrary1 die ILoad implementieren.

Sie könnten dann alle von ihnen instanziiert:

ILoad[] instantiatedTypes = 
    iLoadTypes.Select(t => (ILoad)Activator.CreateInstance(t)).ToArray(); 
+0

Danke, gute Lösung. –

+0

Ich erhalte den folgenden Fehler: 'Eine Implementierung des Abfragemusters für den Quelltyp 'System.Reflection.Assembly' konnte nicht gefunden werden. 'Wo' nicht gefunden. – dotNET

+1

Es gefunden. 'Load (" ClassLibrary1 ")' im obigen Code sollte '.GetExportedTypes();' folgen. – dotNET

4

Sie können keine Instanz einer Schnittstelle erstellen, aber wenn

UserControl1 implements ILoad inteface

Sie resultierende Objekt als ILoad

ILoad uc = (ILoad)Activator.CreateInstance(ob); 
grd.Children.Add(uc); 

Außerdem verwenden können, müssen Sie nicht es über die Schnittstelle behandeln müssen, wenn Sie schreiben

UserControl1 uc = (UserControl1)Activator.CreateInstance(ob); 
grd.Children.Add(uc); 

Mitglieder von ILoad wäre Calla ble as uc.SomeILoadMethod();

+0

Vorausgesetzt, 'ob' ist immer noch ein Typ, der eine Klasse und keine Schnittstelle darstellt. – Guillaume

+0

@Guillaume konstruiert Objekt implementiert ILoad, so dass es direkt verwendet werden kann – archil

+0

OK, aber wie kann ich Typ in Assembly finden, die ** ILoad ** implementiert? –

3

Schnittstelle ist eine Schnittstelle. Es ist eine Vorlage. Warum möchten Sie eine Schnittstelle instanziieren? Implementieren Sie die Schnittstelle und instanziieren Sie diese Klasse. Sie können eine Schnittstelle nicht instanziieren, das macht keinen Sinn.

+1

Natürlich ist es sinnvoll, eine einfache Möglichkeit zu haben, eine Schnittstelle zu instanziieren. Stellen Sie sich DTOs vor. POCOs ohne Verhalten. Sie möchten sie als Schnittstellen erstellen, um sie problemlos in einem Mock-Framework zu verwenden. Wenn Sie jedoch die Schnittstelle implementieren, erhalten Sie im Grunde zwei identische Codeabschnitte, die Sie pflegen müssen. Aus diesem Grund können Sie in einigen Frameworks wie NServiceBus Schnittstellen "instanziieren". Ich sage nicht, dass es leicht mit eingebauten Funktionen wie dem Aktivator gemacht werden kann, ich sage nur, dass Sie das nicht wegblasen können als "macht keinen Sinn" – Morten

4

Was Sie wollen, erreichen Sie mit einem IoC-Container wie `NInject '. Sie können einen Container so konfigurieren, dass er einen konkreten Typ zurückgibt, wenn Sie eine Schnittstelle angefordert haben.

2

Wenn die Bibliothek im Projekt verwiesen wurde Sie verwenden:

static public IEnumerable<Type> GetTypesFromLibrary<T>(String library) 
    { 
     var MyAsemblies = AppDomain.CurrentDomain.GetAssemblies() 
         .Where(a=>a.GetName().Name.Equals(library)) 
         .Select(a=>a); 
     var Exported = MyAsemblies 
         .FirstOrDefault() 
         .GetExportedTypes(); 
     var Asignable = Exported 
         .Where (t=> !t.IsInterface && !t.IsAbstract 
         && typeof(T).IsAssignableFrom(t)) 
         .Select(t=>t) 
         .AsEnumerable(); 
     return Asignable; 
    } 

    static public T GetInstanceOf<T>(String library, String FullClassName) 
    { 
     Type Type = GetTypesFromLibrary<T>(library) 
         .Where(t => t.FullName.Equals(FullClassName)) 
         .FirstOrDefault(); 
     if (Type != null) 
     { 
      T Instance = (T)Activator.CreateInstance(Type); 
      return Instance; 
     } 
     return default(T); 
    } 
2

Das einzige Problem mit der akzeptierten Antwort ist, dass Sie haben müssen eine konkrete Klasse auf Ihrer Baugruppe, die die Schnittstelle implementiert.

Um dies zu vermeiden, habe ich meinen CustomActivator erstellt, der in der Lage ist, zur Laufzeit ein dynamisches Objekt zu erstellen und die gewünschte Schnittstelle zu implementieren.

Ich habe es auf dem Github: https://github.com/fabriciorissetto/CustomActivator

Der Aufruf ist einfach:

CustomActivator.CreateInstance<MyInterface>(); 
Verwandte Themen