7

I'd like to create a method that returns a type (or IEnumerable of types) that implement a specific interface that takes a type parameter -- however I want to search by that generic type parameter itself. This is easier demonstrated as an example:

Method signature that I want:

 public IEnumerable<Type> GetByInterfaceAndGeneric(Type interfaceWithParam, Type specificTypeParameter)

And then if I have the below objects

  public interface IRepository<T> { };
  public class FooRepo : IRepository<Foo> { };
  public class DifferentFooRepo : IRepository<Foo> {};

I then want to be able to do:

  var repos = GetByInterfaceAndGeneric(typeof(IRepository<>), typeof(Foo));

and get an IEnumerable containing the types FooRepo and DifferentFooRepo.

This is very similar to this question, however using that example I would like to search by both IRepository<> and by User.

istrupin
  • 1,423
  • 16
  • 32
  • Your question really is solved exactly by the accepted answer using the `GetAllTypesImplementingOpenGenericType` you just need to add one more condition in each if of `x.GenericTypeArguments[0].IsAssignableFrom(specificTypeParameter)` on it to check for the specific type parameter. – Scott Chamberlain Dec 12 '17 at 18:22
  • Just do `var closedType = interfaceWithParam.MakeGenericType(specificTypeParameter)`. Then your task becomes just "find all types that implement specific interface". – Evk Dec 12 '17 at 18:26
  • I'd say it's even duplicate of this and similar questions:https://stackoverflow.com/q/26733/5311735 – Evk Dec 12 '17 at 19:05
  • @ScottChamberlain Can you kindly elaborate? I know I'm close with this but where am I supposed to add those conditions? I can't seem to get it to work correctly using your proposed solution. – istrupin Dec 12 '17 at 19:32
  • I would contend that this is not a duplicate of stackoverflow.com/q/26733/5311735 . While this linked question is similar, my question is specific to searching by the actual generic interface parameter. I did come across this question in my research, but the difference did not appear trivial to me, as I was unable to solve my problem without the answer @Rainman provided. – istrupin Dec 12 '17 at 22:36

2 Answers2

5

To refactor @lucky's answer, I prefer comparing the types with the generic type definition instead of using the type name:

static readonly Type GenericIEnumerableType = typeof(IEnumerable<>);

//Find all types that implement IEnumerable<T>
static IEnumerable<T> FindAllEnumerableTypes<T>(Assembly assembly) =>
  assembly
  .GetTypes()
  .Where(type =>
    type
      .GetInterfaces()
      .Any(interf =>
        interf.IsGenericType
        && interf.GetGenericTypeDefinition() == GenericIEnumerableType
        && interf.GenericTypeArguments.Single() == typeof(T)));

Alternatively, you can check if interf is assignable from GenericIEnumerableType.MakeGenericType(typeof(T)) or the other way around.

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
2

You can try like this;

    public static IEnumerable<Type> GetByInterfaceAndGeneric(Type interfaceWithParam, Type specificTypeParameter)
    {
        var query =  
            from x in specificTypeParameter.Assembly.GetTypes()
            where 
            x.GetInterfaces().Any(k => k.Name == interfaceWithParam.Name && 
            k.Namespace == interfaceWithParam.Namespace && 
            k.GenericTypeArguments.Contains(specificTypeParameter))
            select x;
        return query;
    }

Usage;

var types = GetByInterfaceAndGeneric(typeof(IRepository<>), typeof(Foo)).ToList();
lucky
  • 12,734
  • 4
  • 24
  • 46
  • This seems to work well in a sample implementation. One question though -- would a similar approach still work if my interface and specificTypeParameter were in different assemblies? Obviously I'd have to change the query a bit but assuming I want to be able to handle that use case, is this still the approach that you would recommend? – istrupin Dec 12 '17 at 20:03
  • Yes, you can handle for different assemblies by changing the query a bit. I suggest you to specify the assemblies which contains repositories. So, is it proper approach ? I don't know, I can't advise to proper way because I don't know the requirements and project design. But, at least I can suggest you that if it isn't must, just create one repository per entity. – lucky Dec 12 '17 at 20:43
  • Sure that makes sense. The above explanation is actually pretty far from my actual implementation, I just wanted to put it in simple terms and make it relateable. In my actual use case, I'm trying to create and configure domain models from some input data based on a number of conditions using custom model creators so that I don't have any data logic in my domain models. I want to be able to pick up the model creators using reflection (they implement IGenerator) so this is the way that I'm doing that. – istrupin Dec 12 '17 at 21:14