为什么协变隐式强制转换忽略泛型约束?
本文关键字:泛型 约束 转换 为什么 | 更新日期: 2023-09-27 18:03:25
static IEnumerable<U> DoSomething<T, U>(IEnumerable<T> a)
where T : U
{
// Works, compiler can compile-time statically cast
// T as U.
T testA = default(T);
U testB = testA;
// And the following works, though:
IEnumerable<string> test2A = null;
IEnumerable<object> test2B = test2A;
// Doesn’t work. Compiler cannot compile-time statically
// cast IEnumerable<T> to IEnumerable<U> even though it is
// out and T is U.
return a;
}
我有一些代码,其中能够执行这种类型的隐式强制转换将节省我编写大量的样板接口实现代码。这似乎是协方差能帮上忙的。但是我总是在上面的return a;
行上得到这个错误:
错误CS0266:不能隐式地将类型"System.Collections.Generic.IEnumerable
"转换为"System.Collections.Generic.IEnumerable"。存在显式转换(您是否缺少强制类型转换?)
为什么是这样的,有没有一种方法可以解决这个问题,而不像return from o in a select o;
那样做?
当我摆弄我的最小复制程序并阅读类似但不相关的关于接口强制转换的问题时,我意识到以下编译:
static IEnumerable<U> DoSomethingElse<T, U>(IEnumerable<T> a)
where T : class, U
{
// Works! Ridik!
return a;
}
并且下面的操作失败并显示相同的错误信息:
static void Blah()
{
// Fails for I bet the same reason that DoSomething{T, U} fails:
IEnumerable<int> a = null;
IEnumerable<object> b = a;
}
错误CS0266:不能隐式地将类型"System.Collections.Generic.IEnumerable
"转换为"System.Collections.Generic.IEnumerable
所以这似乎与。net如何限制某些类型的赋值到引用类型有关,因为在这些情况下装箱要么是错误的事情(例如,你可能假设引用类型,实际上是在一个值类型的副本上工作),要么很难/不可能在运行时实现(给定一个IEnumerable<int>
,你必须实现一个包装适应类。这听起来像是。net不能/不应该在运行时为你做的事情。我认为这是一种。net允许指针式多态性的情况,就其本质而言,它与值类型的概念是不兼容的。
所以,对于我来说,我不需要在我的API中支持值类型,添加class
约束使一切变得神奇!