Search code examples
c#genericsactivator

Generic type casting using Activator.CreateInstance


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.


Solution

  • 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) } );
        }
    }