如何根据类型将类型转换为通用版本?

时间:2009-04-23 09:14:53

标签: c# generics

我在C#中遇到了泛型问题。我必须将许多通用对象存储在一起,但它们的类型参数不同,所以我创建了一个非通用的接口。我正在寻找的是一种在给定类型对象的情况下转换回通用版本的方法。我知道我可以用反射来做,但我想知道是否有更好/更优雅的解决方案。

以下代码说明了问题:

interface ITable
{
   public Type Type { get; }
}

class Table<T> : ITable
{
   public Type Type { get{ return typeof(T); } }
}

class Program
{
   static void Main(string[] args)
   {
      var tables = new Dictionary<string, ITable>();
      ... //insert tables
      DoStuffWithTable(tables["my table"]); //This doesn't work
   }

   public static void DoStuffWithTable<T>(Table<T> table)
   {
      ...//Some work
   }
}

基于我可以从其接口方法获得的Type对象的实例,是否有一种干净的方式来调用泛型DoStuffWithTable方法?

4 个答案:

答案 0 :(得分:2)

如果您从非泛型类型(ITable)开始,那么唯一的方法是通过反射(MakeGenericMethod)。它不是很漂亮或特别快,但它有效...

public static void DoStuffWithUntypedTable(ITable table)
{
    typeof(Program).GetMethod("DoStuffWithTable")
        .MakeGenericMethod(table.Type)
        .Invoke(null, new object[] { table });
}

另外 - 请注意,假设ITable实际上是Table<T>存在一些风险 - 您应该验证这一点,也可能使用接口({{1} })。


编辑:如果确实必须是ITable<T>,那么您可以强制执行此操作(包括子类支持,例如Table<T>

FooTable : Table<Foo>

答案 1 :(得分:1)

问题在于你不知道编译时的类型 - 这是为其定制的泛型。

要调用在执行时只知道类型参数的泛型方法,您基本上需要反射 - 获取泛型方法,调用MakeGenericMethod然后调用返回的方法。

答案 2 :(得分:0)

你需要施放,你实际上需要知道实际的类型,除非它没有意义。

DoStuffWithTable<MyType>((Table<MyType>)tables["my table"]);

如果你想在不知道实际类型的情况下调用它,你应该考虑使该方法不是通用的。

答案 3 :(得分:0)

仿制药和多态性之间存在误解。通常,泛型处理单一类型的事物,其中类型在编译时定义 * ,而多态性是关于不同类型的事物,它们表现出定义为接口或基本类型的通用功能。

您似乎正在尝试创建一个多态类型(具有相同行为的不同类型的东西),其中每个多态实例都由泛型类型定义。

所以,要更新你的代码:

interface ITable
{
   void SomeCommonFunction ();
}

class Table<T> : ITable
{
   void SomeCommonFunction () { do something - T is known at compile time! }
}

class Program
{
   static void Main(string[] args)
   {
      var tables = new Dictionary<string, ITable>();
      ... //insert tables
      tables["my table"].SomeCommonFunction ();
   }
}

现在,如果你想在SomeCommonFunction中做依赖于类型T的不同的事情,那么你想要具有Table类型的特定实例。 C#不允许以C ++可以使用其模板的方式进行泛型类型的特化,因此您必须这样做:

class TableOfInt : ITable
{
   void SomeCommonFunction () { do something different! }
}

*您可以在C#中定义运行时的类型,但这会进入疯狂的反射区域。