一尘不染

为什么“ ref”和“ out”不支持多态?

c#

采取以下措施:

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) {}  
}

为什么会出现上述编译时错误?refout参数都会发生这种情况。


阅读 262

收藏
2020-05-19

共1个答案

一尘不染

=============

更新:我使用此答案作为此博客条目的基础:

为什么ref和out参数不允许类型变化?

有关此问题的更多评论,请参见博客页面。感谢您提出的重大问题。

=============

让我们假设你有课AnimalMammalReptileGiraffeTurtleTiger,具有明显的子类关系。

现在假设您有一个方法void M(ref Mammal m)M可以读写m


您可以将类型的变量传递AnimalM吗?

否。该变量可以包含Turtle,但M将假定它仅包含哺乳动物。A Turtle不是Mammal

结论1ref不能使参数“更大”。(动物比哺乳动物多,因此该变量变得“更大”,因为它可以包含更多的东西。)


您可以将类型的变量传递GiraffeM吗?

M可以写入m,并且M可能要编写一个Tigerm。现在,您已将a Tiger放入实际类型为的变量中Giraffe

结论2ref不能使参数“更小”。


现在考虑N(out Mammal n)

您可以将类型的变量传递GiraffeN吗?

N可以写n,并且N可能要写一个Tiger

结论3out不能使参数“更小”。


您可以将类型的变量传递AnimalN吗?

好吧,为什么不呢? N无法读取n,只能写入,对不对?您将a写入Tiger类型的变量,Animal就已经准备好了,对吧?

错误。规则不是“ N只能写n”。

这些规则是:

1)在正常返回之前N必须先写入。(如果抛出,则所有投注均无效。)n``N``N

2)N必须先写入内容,n然后才能从中读取内容n

这允许发生以下一系列事件:

  • 声明一个xtype 字段Animal
  • x作为out参数传递给N
  • N写入一个,Tigern的别名x
  • 在另一个线程,有人写了一Turtlex
  • N试图阅读的内容n,并发现Turtle它认为是类型的变量Mammal

显然,我们想使之非法。

结论4out不能将参数设为“更大”。


最后得出结论无论是ref也不out参数可能有所不同它们的类型。否则将破坏可验证的类型安全性。

如果您对基本类型理论中的这些问题感兴趣,请考虑阅读我的有关协方差和反方差如何在C#4.0中工作的系列文章

2020-05-19