多态null合并算子

Ruu*_*jah 0 .net c# polymorphism compiler-errors operators

考虑

interface IResult {}
class Result : IResult {}
class Results : IResult {}

class Producer {
    private Results results;
    IResult DoSomething() {
        return results ?? new Result();
    }
}
Run Code Online (Sandbox Code Playgroud)

这会因编译器错误而失败

Operator '??' cannot be applied to operands of type `Result` and `Results`
Run Code Online (Sandbox Code Playgroud)

对我来说,这是出乎意料的行为.考虑到这一点,.NET框架可能会创建一个类型的中间变量Results(左操作数).右操作数Result的类型不同,因此会产生类型转换错误.这个假设是否正确?

如果是,为什么csc不会检测到中间变量的类型IResult?

所以我把代码改成了样子

return results == null ? new Result() : results;
Run Code Online (Sandbox Code Playgroud)

但是这段代码错了

There is no explicit conversion between `Result` and `Results`
Run Code Online (Sandbox Code Playgroud)

为什么?我不指望这个,因为两个实例都符合IResult.

Pat*_*man 7

因为这:

return results ?? new Result();
Run Code Online (Sandbox Code Playgroud)

实际上它试图将最后一个参数的值转换为与第一个参数相同的类型.编译器认为这是您需要的类型.它不使用您分配给它的变量的类型.

你需要一个隐式演员.把它投到IResult你会很好:

return (IResult)results ?? new Result();
Run Code Online (Sandbox Code Playgroud)


Sel*_*enç 5

嗯,这是预期的。因为Result和Results是不一样的类,他们只是实现一个共同的接口,但它们无法转换为对方,这就是为什么你所得到的错误。

如果是,为什么 csc 不会检测到 IResult 类型的中间变量?

这会造成歧义。如果您的类型实现了多个通用接口,例如IFoo. 那么编译器应该选择IResult还是IFoo?你可以说它应该IResult因为返回类型而选择,但是应该发生什么这不是一个 return 语句,这可能是简单的赋值,例如.. 简而言之,C#编译器不会对类型做出假设。

这也在声明C# Specification中 7.13 The null coalescing operator

类型表达a ?? b取决于哪个隐式转换可用偏好operands.In顺序的类型,a ?? bIS A0,A或B,其中A是的式a(前提是一个具有类型),B是的类型b(条件是b 有一个类型),如果 A 是可空类型,则 A0 是 A 的基础类型,否则为 A。具体a ?? b处理如下:

  • [...] 如果A存在并且存在从bto的隐式转换A,则结果类型为A

  • [...] 如果b有一个类型B并且存在从ato的隐式转换B,则结果类型为 B。

  • 否则,a并且b是不兼容的,并发生编译时错误。