采取以下措施:
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= compile-time error:
// "The 'ref' argument doesn't match the parameter type"
}
void Foo(A a) {}
void Foo2(ref A a) {}
}
为什么会出现上面的编译时错误? ref
和 out
参数都会发生这种情况。
最佳答案
=============
更新:我使用这个答案作为这篇博文的基础:
Why do ref and out parameters not allow type variation?
有关此问题的更多评论,请参阅博客页面。感谢您提出很好的问题。
=============
假设您有类 Animal
、Mammal
、Reptile
、Giraffe
、Turtle
code>和Tiger
,具有明显的子类化关系。
现在假设您有一个方法void M(ref Mammal m)
。 M
可以读写m
。
Can you pass a variable of type
Animal
toM
?
没有。该变量可能包含 Turtle
,但 M
将假定它仅包含哺乳动物。 乌龟
不是哺乳动物
。
结论 1:ref
参数不能做得“更大”。 (动物比哺乳动物多,所以变量越来越“大”,因为它可以包含更多的东西。)
Can you pass a variable of type
Giraffe
toM
?
没有。 M
可以写入m
,M
可能想写入一个Tiger
到m
>。现在您已经将 Tiger
放入了一个实际上是 Giraffe
类型的变量中。
结论 2:ref
参数无法“变小”。
现在考虑N(out Mammal n)
。
Can you pass a variable of type
Giraffe
toN
?
没有。 N
可以写到n
,而N
可能想写一个Tiger
。
结论3:out
参数不能做“小”。
Can you pass a variable of type
Animal
toN
?
嗯。
嗯,为什么不呢? N
不能从 n
中读取,它只能写入它,对吗?您将 Tiger
写入类型为 Animal
的变量,一切就绪,对吧?
错了。规则不是“N
只能写入n
”。
简单来说,规则是:
1) N
必须在N
正常返回之前写入n
。 (如果 N
抛出,则所有投注均无效。)
2) N
必须先向 n
写入内容,然后才能从 n
中读取内容。
允许这一系列事件:
- 声明一个类型为
Animal
的字段x
。 - 将
x
作为out
参数传递给N
。 N
将一个Tiger
写入n
,它是x
的别名。- 在另一个线程上,有人将
Turtle
写入x
。 N
尝试读取n
的内容,并在它认为是Mammal 类型的变量中发现了一个
。Turtle
很明显,我们想让它成为非法的。
结论4:out
参数不能“变大”。
最终结论:ref
和out
参数都不能改变它们的类型。否则就是破坏可验证的类型安全。
如果您对基本类型论中的这些问题感兴趣,请考虑阅读 my series on how covariance and contravariance work in C# 4.0 .
关于c# - 为什么 'ref'和 'out'不支持多态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1207144/