2017-09-03 4 views
2

J'ai une hiérarchie d'interfaces génériques, où chaque interface est liée à IOperator<T1,T2>.Instancier toutes les classes qui implémentent une instance d'une interface générique

interface IOperator<T1, T2> 
{ 
    Func<T1, T2, bool> GetFunc() 
} 

IOperator : IOperator<object, object> 

interface IMatchingOperator : IOperator<string, string> { } 


interface IComparisonOperator<T1, T2> : IOperator<T1, T2> 
    where T1: IComparable<T2> { } 

interface IComparisonOperator<T> : IComparisonOperator<T, T> 
    where T: IComparable<T> { } 

interface IComparisonOperator : IComparisonOperator<IComparable, object> 

J'ai beaucoup de classes (non génériques) qui mettent en œuvre une ou plusieurs de ces interfaces, par exemple:

class GreaterThanOperator : 
    IComparisonOperator, 
    IComparisonOperator<decimal>, 
    IComparisonOperator<DateTime>, 
    IComparisonOperator<DateTime, string> 
{ ... } 

class EqualComparator: IOperator 

class RegexOperator : IMatchingOperator { ... } 

Maintenant, je veux un pour créer une usine qui peut charger et instancier chaque classe dans les assemblys qui implémente en quelque sorte l'interface parent "IOperator" et la place dans une collection.

J'ai essayé avec:

AppDomain.CurrentDomain.GetAssemblies() 
       .SelectMany(x => x.GetTypes()) 
       .Where(
        x => x.IsGenericType 
        && x.GetGenericTypeDefinition() == typeof(IOperator<,>) 
        && !x.IsInterface && !x.IsAbstract)) 
       .Select(x => Activator.CreateInstance(x)).ToList(); 

mais il ne fonctionne pas.

Je souhaite que la liste finale contienne une instance de chaque classe IOperator. Je vais ensuite parcourir les objets avec la réflexion pour voir quels types génériques ils utilisent.

+0

première question, pourquoi vous essayez de le faire, il semble que vous cherchez technique 'Lazy loading'. –

+0

Ceci serait exécuté dans un constructeur statique d'une usine. La raison en est que je veux connaître tous les opérateurs qui existent. Comment pourrais-je implémenter une approche de chargement paresseux? – AFusco

+0

vous instanciez des types quand vous en avez besoin et si vous le souhaitez, vous pouvez également les mettre en cache dans une propriété statique. –

Répondre

2

La clause Where ne doit pas vérifier le type générique, car vos classes, GreaterThanOperator etc., ne sont pas elles-mêmes des classes génériques. De plus, IOperator<,> est et non une définition de vos types: c'est une définition de type de l'une des interfaces implémentées par celui-ci.

Voici comment vous pouvez effectuer la sélection:

var res = AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(x => x.GetTypes()) 
    .Where(x => 
     !x.IsAbstract 
    && !x.IsInterface 
    && x.GetInterfaces().Any(i => 
      i.IsGenericType() 
     && i.GetGenericTypeDefinition() == typeof(IOperator<,>) 
     ) 
    ).Select(x => Activator.CreateInstance(x)).ToList();