采取以下措施:
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
和Tiger
,它们具有明显的子类关系。
现在假设您有一个void M(ref Mammal m)
方法。 M
可以读写m
。
Can you pass a variable of type
Animal
toM
?
否。该变量可以包含
Turtle
,但是M
将假定它仅包含哺乳动物。 Turtle
不是Mammal
。结论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
中写入内容。这允许发生以下一系列事件:
x
的字段Animal
。 x
作为out
参数传递给N
。 N
将Tiger
写入n
中,它是x
的别名。 Turtle
写入x
。 N
尝试读取n
的内容,并在它认为是Turtle
类型的变量中发现Mammal
。 显然,我们想使之非法。
结论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/45887164/