C# 多态零合并算子

C# 多态零合并算子,c#,.net,compiler-errors,polymorphism,operators,C#,.net,Compiler Errors,Polymorphism,Operators,考虑 interface IResult {} class Result : IResult {} class Results : IResult {} class Producer { private Results results; IResult DoSomething() { return results ?? new Result(); } } 由于编译器错误,此操作失败 Operator '??' cannot be applied to

考虑

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

class Producer {
    private Results results;
    IResult DoSomething() {
        return results ?? new Result();
    }
}
由于编译器错误,此操作失败

Operator '??' cannot be applied to operands of type `Result` and `Results`
对我来说,这是意想不到的行为。考虑到这一点,.NET framework可能会创建类型为
Results
(左操作数)的中间变量。右操作数
Result
的类型不同,因此会产生类型转换错误。这个假设正确吗

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

所以我把代码改成

return results == null ? new Result() : results;
然而,这段代码有错误

There is no explicit conversion between `Result` and `Results`

为什么??我不希望出现这种情况,因为这两个实例都符合IResult。

这是意料之中的。因为
Result
Results
不是同一个类,它们只是实现了一个公共接口,但它们不能相互转换,这就是为什么会出现错误

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

这会造成歧义。如果您的类型实现了多个公共接口(比如
IFoo
),会发生什么。然后编译器应该选择
IResult
IFoo
?您可以说,由于返回类型的原因,它应该选择
IResult
,但是应该发生什么呢?这不是一个返回语句,例如,这可能是一个简单的赋值。。所以简而言之,
C#
编译器不会对类型进行假设

这也在
7.13中的
C#规范
中说明了空合并运算符

表达式的类型
a??b
取决于操作数上可用的隐式转换。按优先顺序,
a的类型??b
A0
A
b
,其中
A
A
的类型(前提是A有一个类型),
b
b
的类型(前提是b有一个类型),如果A是可为空的类型,A0是A的基础类型,或者A不是。具体来说,
a??b
处理如下:

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

  • […]如果
    b
    具有类型
    b
    ,并且存在从
    a
    b
    的隐式转换,则结果类型为b

  • 否则,
    a
    b
    不兼容,会发生编译时错误

因为:

return results ?? new Result();
实际上,它试图将最后一个参数的值强制转换为与第一个参数相同的类型。编译器认为这是您需要的类型。它不使用您分配给它的变量的类型

你需要一个隐式演员阵容。将其投射到
IResult
即可:

return (IResult)results ?? new Result();

左操作数的类型是
Results
,而不是
IResult
。您需要强制转换才能让编译器理解这一点。这是正确的答案。替代语法:return(结果为IResult)??新结果();它不使用您分配给它的变量的类型。这实际上与返回类型无关。即使将返回类型更改为
Result
Results
此表达式仍然无效:
Results??新结果()正如您所解释的,您可能期望它会这样做。但显然不是。仅供参考,我否决了你,因为根据规范,你错了。编译器不使用第一个操作数的类型。例如,这也会编译:
返回结果??((IResult)新结果())@Selman22:谢谢你让我知道。你说得对。您能验证更新吗?这可以用更好的措辞-如果
Result
Results
都被各自的类型引用,那么,是的,它们是不兼容的类型。但是,它们都实现了一个公共接口,如果对象是由接口类型而不是实现类型引用的,那么这会使它们兼容。说它们不是“兼容类型”是误导。(编辑:这是关于你的原始帖子,在编辑之前,你有完整和正确的答案,因此我将此标记为答案。C#可能会添加一个子句,在这种情况下可以应用返回类型推断。