【发布时间】:2011-06-21 00:46:38
【问题描述】:
我想知道dynamic 在用作泛型类型参数时是否在语义上等同于object。如果是这样,我很好奇为什么存在这种限制,因为在为变量或形式参数赋值时两者是不同的。
我用 C# 4.0 编写了一个小实验来梳理一些细节。我定义了一些简单的接口和实现:
interface ICovariance<out T> { T Method(); }
interface IContravariance<in T> { void Method(T argument); }
class Covariance<T> : ICovariance<T>
{
public T Method() { return default(T); }
}
class Contravariance<T> : IContravariance<T>
{
public void Method(T argument) { }
}
实验的有趣细节:
class Variance
{
static void Example()
{
ICovariance<object> c1 = new Covariance<string>();
IContravariance<string> c2 = new Contravariance<object>();
ICovariance<dynamic> c3 = new Covariance<string>();
IContravariance<string> c4 = new Contravariance<dynamic>();
ICovariance<object> c5 = new Covariance<dynamic>();
IContravariance<dynamic> c6 = new Contravariance<object>();
// The following statements do not compile.
//ICovariance<string> c7 = new Covariance<dynamic>();
//IContravariance<dynamic> c8 = new Contravariance<string>();
// However, these do.
string s = new Covariance<dynamic>().Method();
new Contravariance<string>().Method((dynamic)s);
}
}
带有c1 和c2 的前两个语句表明基本的协变和逆变是有效的。然后我使用c3 和c4 来表明dynamic 可以以相同的方式用作泛型类型参数。
带有c5 和c6 的语句表明从dynamic 到object 的转换始终有效。这并不奇怪,因为object 是所有其他类型的祖先。
c7 和 c8 的最终实验是我开始感到困惑的地方。这意味着返回dynamic 对象的方法不能替代返回string 对象的方法,同样接受string 对象的方法也不能采用dynamic 对象。带有赋值和方法调用的最后两条语句表明情况显然并非如此,因此我感到困惑。
我想了想,想知道这是否是为了防止程序员在类型转换之间使用ICovariance<dynamic>作为垫脚石,这会导致运行时错误,例如:
ICovariance<dynamic> c9 = new Covariance<Exception>();
ICovariance<string> c10 = c9;
// While this is definitely not allowed:
ICovariance<string> c11 = new Covariance<Exception>();
然而,这在 dynamic 的情况下是不能令人信服的,因为无论如何我们都会失去类型安全性:
dynamic v1 = new Exception();
string v2 = v1;
换句话说,问题是“为什么dynamic 的语义在赋值和协变/逆变与泛型之间存在差异?”
【问题讨论】:
-
希望 Eric 来访并给我们启示 :)
-
我正在尽我所能地投射
Summon Eric Lippert。 -
各位,如果有什么想引起我注意的,请使用我博客上的“联系”链接。
-
我不敢相信它成功了!
-
你们太古怪了。
标签: c# .net generics dynamic c#-4.0