0

I have an interface

public interface ISomething<TValue>
    where TValue : IConvertible
{
    ...
}

Then I also have some non-generic class with a generic method:

public class Provider
{
    public static void RegisterType<TValue>(ISomething<TValue> instance)
        where TValue : IConvertible
    {
        ...
    }
}

This seems all fine until I want to automatically register all applicable types in my particular assembly.

public void InitializeApp()
{
    foreach(Type t in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ISomething<>).IsAssignableFrom(T)))
    {
        // ERROR
        Provider.RegisterType(Activator.CreateInstance(t));
    }
}

This code results in error as argument type can't be inferred from usage. I should either

  1. provide explicit generic type with my generic method RegisterType (I don't think I can do this due to dynamic nature of my code) or
  2. cast results from Activator.CreateInstance to appropriate type so argument type could be inferred from usage

But I don't know how to do either? Maybe there's a third option I'm not aware of.

Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
  • Have you considered invoking `RegisterType` via reflection and `MakeGenericMethod`? Either that or you sould probably have a non generic `ISomething` and an overload of `RegisterType` that uses that. – Kirk Woll Jun 03 '14 at 18:35

1 Answers1

3

Generics are a compile-time feature, meaning that the generic types must be known at compile time. So your RegisterType method can't be used when you only know the type at runtime, since there's no way for the compiler to deduce the generic parameter.

You have a couple options here. You can either use reflection to call the correct version of RegisterType (as suggested in the comments), or you can create an additional non-generic overload of RegisterType that accepts an object and figures out the execution-time type from that.

For the former, that would look something like this:

public void InitializeApp()
{
    foreach(Type t in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ISomething<>).IsAssignableFrom(T)))
    {
        var methodInfo = typeof( Provider ).GetMethod( "RegisterType", BindingFlags.Static );
        var registerTypeMethod = methodInfo.MakeGenericMethod( t );
        registerTypeMethod.Invoke( null, new[] { Activator.CreateInstance(t) } );
    }
}
Kyle
  • 6,500
  • 2
  • 31
  • 41
  • You almost got it right so I'm accepting your answer as the correct one because it led me to solution. For generic type inheritance `IsAssignableForm` won't do the trick when asking about open generic type, because it can't be instantiated. [This answer helped](http://stackoverflow.com/a/503359/75642) in this regard. And also when calling `MakeGenericMethod` we have to provide generic type argument instead of type itself as you did. – Robert Koritnik Jun 04 '14 at 19:36