Puis-je utiliser Activator.CreateInstance avec une interface?

J'ai un exemple:

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

Là, je crée une instance d'une classe, mais comment puis-je créer une instance d'une classe qui implémente une interface? c'est-à-dire UserControl1 implémente l'interface ILoad .

U: I can cast object to interface later, but I don't know which type in the assemblies implements the interface.

0
Vous ne pouvez pas créer une instance d'une interface; Vous pouvez créer la classe implémentant l'interface et la passer en tant qu'interface.
ajouté l'auteur Marco, source
Vous ne pouvez pas instancier un objet de type ILoad, c'est une interface.
ajouté l'auteur JustinDanielson, source

6 Réponses

C'est un code que j'ai utilisé quelques fois. Il trouve tous les types dans un assembly qui implémentent une certaine interface:

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

Ensuite, vous avez tous les types dans ClassLibrary1 qui implémentent ILoad .

Vous pouvez ensuite les instancier tous:

ILoad[] instantiatedTypes = 
    iLoadTypes.Select(t => (ILoad)Activator.CreateInstance(t)).ToArray();
0
ajouté
Comment puis-je lancer, Si l'interface est générique ILoad <> ????
ajouté l'auteur barteloma, source
Merci, bonne solution.
ajouté l'auteur Arman Hayots, source
J'obtiens l'erreur suivante: Impossible de trouver une implémentation du modèle de requête pour le type de source 'System.Reflection.Assembly'. 'Où' pas trouvé.
ajouté l'auteur dotNET, source
Je l'ai trouvé. Load ("ClassLibrary1") dans le code ci-dessus doit être suivi de .GetExportedTypes (); .
ajouté l'auteur dotNET, source
@dotNET Ouais cet appel devrait être là. Je l'ai ajouté maintenant.
ajouté l'auteur Botz3000, source
@bookmarker Vous devez connaître le paramètre type pour lancer. Si vous ne le savez pas, vous pouvez utiliser une interface de base non générique. Les classes génériques ou les interfaces ne sont plus si faciles à utiliser si vous ne connaissez pas le paramètre type.
ajouté l'auteur Botz3000, source
Salut. Une idée sur la façon de le faire dans une classe portable? 't' ne semble pas avoir IsInterface ou IsAbstract et Type n'a pas IsAssignableFrom. J'essaie d'activer une instance à partir d'une interface dans un projet de bibliothèque de classes portable afin de pouvoir l'utiliser dans Xamarin.
ajouté l'auteur shahar eldad, source

Vous ne pouvez pas créer une instance d'une interface, mais si

UserControl1 implémente l'interface ILoad

you can use resulting object as ILoad

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

De plus, vous n'avez pas besoin de le traiter via l'interface, si vous écrivez

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

Members of ILoad would be callable as uc.SomeILoadMethod();

0
ajouté
OK, mais comment puis-je trouver le type dans l'assembly, qui implémente ILoad ?
ajouté l'auteur Arman Hayots, source
Fourni ob est toujours un type représentant une classe et non une interface.
ajouté l'auteur Guillaume, source
@Guillaume objet construit implémente ILoad, de sorte qu'il peut être utilisé directement
ajouté l'auteur archil, source

L'interface est une interface. C'est un modèle. Pourquoi voudriez-vous instancier une interface? Implémentez l'interface et instanciez cette classe. Vous ne pouvez pas instancier une interface, cela n'a pas vraiment de sens.

0
ajouté
Bien sûr, il est logique d'avoir un moyen facile d'instancier une interface. Imaginez les DTO. POCOs sans comportement. Vous voulez les créer en tant qu'interface afin de les utiliser facilement dans un cadre fictif, mais lorsque vous implémentez l'interface, vous vous retrouvez avec deux parties de code identiques que vous devez maintenir. C'est pourquoi certains frameworks, comme NServiceBus, vous permettent d '"instancier des interfaces". Je ne dis pas que cela peut être fait facilement avec des fonctionnalités intégrées comme l'activateur, je dis juste que vous ne pouvez pas faire sauter c
ajouté l'auteur Morten, source

Ce que vous voulez peut être réalisé en utilisant un conteneur IoC comme `NInject '. Vous pouvez configurer un conteneur pour renvoyer un type concret lorsque vous avez demandé une interface.

0
ajouté

Si la bibliothèque a été référencée dans le projet, vous pouvez utiliser:

    static public IEnumerable GetTypesFromLibrary(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(String library, String FullClassName)
    {
        Type Type = GetTypesFromLibrary(library)
                        .Where(t => t.FullName.Equals(FullClassName))
                        .FirstOrDefault();
        if (Type != null)
        {
            T Instance = (T)Activator.CreateInstance(Type);
            return Instance;
        }
        return default(T);
    }
0
ajouté

Le seul problème avec la réponse acceptée est que vous devez avoir une classe concrète sur votre assembly qui implémente l'interface.

Pour éviter cela, j'ai créé mon CustomActivator qui est capable de créer un objet dynamique à l'exécution et de le faire implémenter l'interface souhaitée.

I put it on the github: https://github.com/fabriciorissetto/CustomActivator

L'appel est simple:

CustomActivator.CreateInstance();
0
ajouté