c# - 为什么 'ref'和 'out'不支持多态?

标签 c# polymorphism out-parameters ref-parameters

采取以下措施:

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参数都会发生这种情况。

最佳答案

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

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

Why do ref and out parameters not allow type variation?

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

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

假设您有类AnimalMammalReptileGiraffeTurtleTiger,它们具有明显的子类关系。

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

Can you pass a variable of type Animal to M?



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

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

Can you pass a variable of type Giraffe to M?



不可以。M可以写入m,并且M可能想将Tiger写入m。现在,您已将Tiger放入实际上是Giraffe类型的变量中。

结论2 :不能将ref参数设置为“更小”。

现在考虑N(out Mammal n)

Can you pass a variable of type Giraffe to N?



不可以。N可以写入n,而N可能要写入Tiger

结论3 :不能将out参数设置为“更小”。

Can you pass a variable of type Animal to N?





好吧,为什么不呢? N无法从n读取,只能对其写入,对吗?您将Tiger写入Animal类型的变量,您已经设置好了吧?

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

这些规则是:

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

2)N必须先从n中读取内容,然后再向n中写入内容。

这允许发生以下一系列事件:
  • 声明类型为x的字段Animal
  • x作为out参数传递给N
  • NTiger写入n中,它是x的别名。
  • 在另一个线程上,有人将Turtle写入x
  • N尝试读取n的内容,并在它认为是Turtle类型的变量中发现Mammal

  • 显然,我们想使之非法。

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

    最终结论: refout参数都不能改变其类型。否则将破坏可验证的类型安全性。

    如果您对基本类型理论中的这些问题感兴趣,请考虑阅读my series on how covariance and contravariance work in C# 4.0

    关于c# - 为什么 'ref'和 'out'不支持多态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45887164/

    相关文章:

    javascript - JavaScript 中的方法继承

    c# - 使用多线程为递归类实例创建新对象

    java - 不使用instanceof的向下转型和多态性? ( java )

    javascript - SPA - Firebase 和 .Net WebApi 2 身份验证

    c# - C#中对象实例化左侧的抽象类

    C# - 在线程中使用带有 "out"参数的函数

    java - MyBatis注解调用Stored Procedure并获取Out Params

    c# - 在 C# 中模拟可选 "out"参数的模式?

    c# - ASP.NET WebHook 和 Web 服务之间的区别?

    c# - 在哪里可以找到有关类和方法抛出的异常的信息?