C#中的泛型,使用变量的类型作为参数[重复]

Posted

技术标签:

【中文标题】C#中的泛型,使用变量的类型作为参数[重复]【英文标题】:Generics in C#, using type of a variable as parameter [duplicate] 【发布时间】:2011-01-07 15:33:37 【问题描述】:

我有一个通用方法

bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

我如何通过以下方式使用该方法:

Type t = entity.GetType();
DoesEntityExist<t>(entityGuid, transaction);

我不断收到愚蠢的编译错误:

类型或命名空间名称“t”可以 找不到(您是否缺少使用 指令还是程序集引用?)

DoesEntityExist<MyType>(entityGuid, transaction);

完美运行,但我不想每次都使用 if 指令来调用具有单独类型名称的方法。

【问题讨论】:

你不能那样使用泛型(第一个例子) 另外:为什么 DoesEntityExist() 方法需要事务参数? ***.com/questions/687363/… 和 ***.com/questions/2078914/c-dynamic-generic-type 的类似问题 @MitchWheat,也许他想检查该实体是否存在于数据库中。 这不是一个重复的问题。这是另一个问题的不同方面 - 另一个问题的答案不符合该问题的答案。 【参考方案1】:

关于泛型的重点是为编译时类型提供安全性——这意味着需要在编译时知道类型。

可以调用只有在执行时才知道类型的泛型方法,但你必须使用反射:

// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
                             .MakeGenericMethod(new Type[]  t );
method.Invoke(this, new object[]  entityGuid, transaction );

伊克。

您能否将您的 调用 方法改为泛型,并将您的类型参数作为类型参数传递,从而将决策推到更高的堆栈级别?

如果您能向我们提供有关您正在做的事情的更多信息,那将会有所帮助。有时你可能需要像上面那样使用反射,但是如果你选择了正确的点来做,你可以确保你只需要做一次,并且让低于该点的所有东西都以正常的方式使用类型参数。

【讨论】:

我认为这个答案中最重要的是ick。那和编译时类型安全. @Mitch:问题在于有时这是必要的。它很丑陋,应该尽可能避免......但偶尔你需要它。 @JonSkeet: 有没有办法使用dynamic 关键字来适应这种情况? @MoslemBenDhaou:不,因为这里没有用于类型推断的实例。 @MoslemBenDhaou:你可以通过一个中间泛型方法使用dynamic 来推断类型。如果这还不够信息,请提出一个新问题 - 它与这个问题有很大不同,因此在 cmets 中追求它并不理想。【参考方案2】:

解决这个问题的一种方法是使用隐式转换:

bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

这样称呼它:

DoesEntityExist(entity, entityGuid, transaction);

更进一步,你可以把它变成一个扩展方法(它需要在一个静态类中声明):

static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

这样称呼:

entity.DoesEntityExist(entityGuid, transaction);

【讨论】:

这太棒了!有什么缺点吗?似乎比使用反射更优雅地解决原始问题?? 只有在声明类型足够的情况下才有效。如果实体被声明为对象怎么办? JonSkeet 的解决方案创建了泛型版本,其中 T 是真实类型,而不是声明的类型。 我不知道使用T约束可以让你在调用方法时绕过类型参数。当我可以做Sort(input)时,我试图找出类似Sort&lt;typeof(input)&gt;(input)的东西!【参考方案3】:

我不确定我是否正确理解了您的问题,但您可以这样编写代码:

bool DoesEntityExist<T>(T instance, ....)

您可以通过以下方式调用该方法:

DoesEntityExist(myTypeInstance, ...)

这样你就不需要显式编写类型,框架会自动从实例中获取类型。

【讨论】:

【参考方案4】:

你不能按照你描述的方式使用它。关于泛型类型的要点是,尽管您可能在“编码时”不知道它们,但编译器需要能够在编译时解析它们。为什么?因为在底层,编译器会离开并为“开放”泛型类型的每种不同用法创建一个新类型(有时称为封闭泛型类型)。

也就是说,编译后,

DoesEntityExist<int>

是不同的类型
DoesEntityExist<string>

这就是编译器能够确保编译时类型安全的方式。

对于您描述的场景,您应该将类​​型作为可在运行时检查的参数传递。

正如其他答案中提到的那样,另一个选项是使用反射从开放类型创建封闭类型,尽管这可能在我所说的极端利基场景之外的任何情况下被推荐。

【讨论】:

以上是关于C#中的泛型,使用变量的类型作为参数[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用枚举作为泛型类型参数 [重复]

第2张 C#中的泛型

C#中的泛型是啥意思?

如何从 C# 中的泛型类型数组中选择一组随机值?

C#中的泛型

转载:C#中的泛型