使用Activator.CreateInstance进行泛型类型转换

时间:2014-06-03 18:33:15

标签: c# generics activator

我有一个界面

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

然后我还有一些带有泛型方法的非泛型类:

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

这似乎一切正常,直到我想在我的特定程序集中自动注册所有适用的类型。

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

此代码导致错误,因为参数类型无法从使用中推断出来。我应该

  1. 使用我的通用方法RegisterType提供显式泛型类型(由于代码的动态特性,我不认为我可以这样做)或
  2. Activator.CreateInstance的结果转换为适当的类型,因此可以从用法
  3. 推断出参数类型

    但我不知道怎么做?也许还有我不知道的第三种选择。

1 个答案:

答案 0 :(得分:2)

泛型是一个编译时功能,这意味着必须在编译时知道泛型类型。因此,当您只知道运行时的类型时,不能使用RegisterType方法,因为编译器无法推导出通用参数。

这里有几个选项。您可以使用反射来调用RegisterType的正确版本(如注释中所建议的),或者您可以创建一个额外的非泛型重载RegisterType,它接受​​一个对象并指出执行 - 时间类型。

对于前者,这看起来像这样:

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