为方法调用动态设置类型

Set type dynamically for method call

我有一个静态函数:

    public static MyCollection<T> Parse<T>(string? json) where T : BaseClass
    {
       ...
    }

而且效果很好。它根据类型在内部做出决定并生成正确的集合。

但是,我想要的集合基于来自另一个来源的文件名,我希望有一个集合并动态设置类型,如:

   Type t;
   if (name == "Certain name") t = typeof(CertainChildClassOfBaseClass);
   if (name == "Other name") t = typeof(OtherChildClassOfBaseClass);

   var myCollection = ParsingService.Parse<t>(jsonString);

这显然行不通,但我正在尝试的可能吗?我真的不想写一堆内容几乎相同的 if/else 块,这样每个块都可以有不同的类型(我已经在 Parse 函数中编写了那些特定于类型的块 - 做同样的分支两次似乎我犯了一个更根本的错误)。我愿意接受有关如何以“正确”方式执行此操作的建议。也许我必须通过反思来做到这一点,这并没有让我兴奋,但这并不是世界末日。一个可能的问题是我的解析服务是静态的。

乐于助人。

通常,我会建议使 Parse 非泛型,然后进行泛型重载:

public static MyCollection<BaseClass> Parse(Type type, string? json)
{
   ...
}

public static MyCollection<T> Parse<T>(string? json) where T : BaseClass
{
   return (MyCollection<T>)Parse(typeof(T), json);
}

但是你不能使 MyCollection 逆变,因为它是一个具体的 class,因此强制转换是非法的。而且无论如何,逆变容器使用起来很危险(例如,看看数组)。

另一种方法是使用反射来获取所需方法的版本(称为“关闭”泛型类型的过程):

var genericMethod = typeof(/* class containing Parse */).GetMethod("Parse");
var method = genericMethod.MakeGenericMethod(type); // type will be substituted for your 'T', above
object collection = method.Invoke(json); // call the method

在这里我们遇到了另一个障碍:collection 的类型将是 object,您需要将其转换为其他类型。但是你不能使用 MyCollection<T> 因为你不知道 T,你不能使用 MyCollection<BaseClass> 因为,好吧,又没有逆变。

所以真正的主要障碍是 MyCollection 类型。只要是那样,您就没有简单的方法可以绕过它。您可以改为 return 一个非泛型集合,例如 ICollectionIList,但这样您就失去了类型安全性,您将不得不在以后继续转换。这完全取决于你。