AFusco
AFusco

Reputation: 474

Instantiate all classes that implement an instance of a generic interface

I have a hierarchy of generic interfaces, where every interface is related to IOperator<T1,T2>.

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>

I have a lot of classes (not generic) that implement one or more of these interfaces, for example:

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

class EqualComparator: IOperator

class RegexOperator : IMatchingOperator { ... }

Now, I want a to create a factory that can load and instantiate every class in the assemblies that in some way implements the parent interface "IOperator", and put it in a collection.

I tried with:

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

but it doesn't work.

I want the final list to hold one instance of each IOperator class. I will then navigate the objects with reflection to see what generic types they use.

Upvotes: 3

Views: 1237

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727077

The Where clause should not check for generic type, because your classes, GreaterThanOperator etc., are not themselves generic classes. In addition, IOperator<,> is not a definition of your types: it is a type definition of one of the interfaces implemented by it.

Here is how you could perform the selection:

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

Upvotes: 4

Related Questions