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<typeof(input)>(input)
的东西!【参考方案3】:
我不确定我是否正确理解了您的问题,但您可以这样编写代码:
bool DoesEntityExist<T>(T instance, ....)
您可以通过以下方式调用该方法:
DoesEntityExist(myTypeInstance, ...)
这样你就不需要显式编写类型,框架会自动从实例中获取类型。
【讨论】:
【参考方案4】:你不能按照你描述的方式使用它。关于泛型类型的要点是,尽管您可能在“编码时”不知道它们,但编译器需要能够在编译时解析它们。为什么?因为在底层,编译器会离开并为“开放”泛型类型的每种不同用法创建一个新类型(有时称为封闭泛型类型)。
也就是说,编译后,
DoesEntityExist<int>
与
是不同的类型DoesEntityExist<string>
这就是编译器能够确保编译时类型安全的方式。
对于您描述的场景,您应该将类型作为可在运行时检查的参数传递。
正如其他答案中提到的那样,另一个选项是使用反射从开放类型创建封闭类型,尽管这可能在我所说的极端利基场景之外的任何情况下被推荐。
【讨论】:
以上是关于C#中的泛型,使用变量的类型作为参数[重复]的主要内容,如果未能解决你的问题,请参考以下文章