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
RegisterType
(I don't think I can do this due to dynamic nature of my code) orActivator.CreateInstance
to appropriate type so argument type could be inferred from usageBut I don't know how to do either? Maybe there's a third option I'm not aware of.
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) } );
}
}