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

本文关键字:泛型 类型转换 Activator CreateInstance 使用 | 更新日期: 2023-09-27 18:06:45

我有一个接口

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. 推断参数类型。

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

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

泛型是编译时特性,这意味着在编译时必须知道泛型类型。所以当你只在运行时知道类型时,你的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) } );
    }
}