C# 如何在给定类型的情况下将类型转换为泛型版本?

C# 如何在给定类型的情况下将类型转换为泛型版本?,c#,generics,C#,Generics,我在C#中的泛型方面有点麻烦。我必须将许多泛型对象存储在一起,但它们的类型参数不同,因此我创建了一个它们实现的非泛型接口。我要寻找的是一种转换回通用版本的方法,给定一个类型对象。我知道我可以通过反射来实现,但我想知道是否有更好/更优雅的解决方案 以下代码说明了该问题: interface ITable { public Type Type { get; } } class Table<T> : ITable { public Type Type { get{ retur

我在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
   }
}
interface-ITable
{
公共类型类型{get;}
}
类表:ITable
{
公共类型类型{get{return typeof(T);}
}
班级计划
{
静态void Main(字符串[]参数)
{
var tables=newdictionary();
…//插入表
DoStuffWithTable(表[“我的表]);//这不起作用
}
公共静态无效DoStuffWithTable(表格)
{
…一些工作
}
}

是否有一种干净的方法可以根据从接口方法获得的类型对象实例调用泛型
DoStuffWithTable
方法?

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

public static void DoStuffWithUntypedTable(ITable table)
{
    typeof(Program).GetMethod("DoStuffWithTable")
        .MakeGenericMethod(table.Type)
        .Invoke(null, new object[] { table });
}
顺便说一句-请注意,假设
ITable
实际上是一个
,存在一定的风险-您可能应该验证这一点,还可以使用接口(
ITable


编辑:如果它确实必须是一个
,那么您可以强制执行它(包括子类支持,例如
FooTable:Table
,如下所示:

public static void DoStuffWithUntypedTable(object table)
{
    Type type = table.GetType();
    while (type != typeof(object))
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition()
              == typeof(Table<>))
        {
            typeof(Program).GetMethod("DoStuffWithTable")
                .MakeGenericMethod(type.GetGenericArguments()[0])
                .Invoke(null, new object[] { table });
            return;
        }
        type = type.BaseType;
    }
    throw new ArgumentException("Not a Table<T> or subclass");
}
publicstaticvoiddostufwithuntypedtable(对象表)
{
Type Type=table.GetType();
while(type!=typeof(object))
{
if(type.IsGenericType&&type.GetGenericTypeDefinition()
==类型(表格))
{
typeof(Program).GetMethod(“DoStuffWithTable”)
.MakeGenericMethod(类型.GetGenericArguments()[0])
.Invoke(null,新对象[]{table});
返回;
}
type=type.BaseType;
}
抛出新ArgumentException(“不是表或子类”);
}

您需要强制转换,您实际上需要知道实际的类型,除非它没有意义

DoStuffWithTable<MyType>((Table<MyType>)tables["my table"]);
dostufwithtable((Table)tables[“我的Table]”);

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

< P>问题是,您不知道编译时的类型——泛型是为其量身定做的。


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

泛型和多态性之间存在误解。泛型通常处理在编译时定义类型的单一类型的事情时间*,而多态性是关于不同类型的事物,它们展示了定义为接口或基类型的公共功能

您似乎试图创建一个多态类型(不同类型的事物表现出相同的行为),其中每个多态实例都由一个泛型类型定义

因此,要更新您的代码:

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

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

是的,泛型并不是这个问题的解决方案,多态性很可能是你想要的答案。我也很担心,但泛型方法在第三部分库中,因此没有办法避免它。+1同意,如果你做不到的话(这也没什么意义:P),只需将DoStuffWithTable设置为非泛型,并将其作为一种旁白使用即可-有趣的是,这可能通过
dynamic
在C#4.0中起作用-不过,我必须再次检查泛型分辨率。我认为这是使用大锤敲入图钉的情况。我认为这是一个设计/理解语言问题。我可能错了当然。我会将上述分类为代码气味(介于辛辣的布里干酪和稍微过时的鸡蛋之间)。是的,但考虑到要求,以及这些类来自第三方库的事实,这是唯一可行的方法。如果你不这么认为,请用代码显示;-pEnforcing可以简单得多:typeof(Table)。MakeGenericType(table.Type).IsInstanceOfType(table)
class TableOfInt : ITable
{
   void SomeCommonFunction () { do something different! }
}