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?

有关此问题的更多评论,请参阅博客页面。感谢您提出很好的问题。

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

假设您有类 AnimalMammalReptileGiraffeTurtle code>和Tiger,具有明显的子类化关系。

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


Can you pass a variable of type Animal to M?

没有。该变量可能包含 Turtle,但 M 将假定它仅包含哺乳动物。 乌龟 不是哺乳动物

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


Can you pass a variable of type Giraffe to M?

没有。 M 可以写入mM 可能想写入一个Tigerm >。现在您已经将 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 中读取内容。

允许这一系列事件:

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

很明显,我们想让它成为非法的。

结论4:out参数不能“变大”。


最终结论:refout 参数都不能改变它们的类型。否则就是破坏可验证的类型安全。

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

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

相关文章:

c++ - 类成员函数内的虚函数调用

c# - DynamicMethod 和输出参数?

java - MySQL CallableStatement.getObject 具有不一致的行为

c# - 从 c# 到 mongodb 正确插入 DateTime

c# - 查询以检测重复行

c# - 没有访客模式的动态调度

java - 使用 Jackson 对 JSON 文件进行多态反序列化

iphone - 传出参数

c# - 通用存储库 - 表达式数组 <Func<T, TProperty>> 错误

c# - Android 通过 tcp 套接字从 c# 服务器接收图像