【问题标题】:Polymorphic null coalescing operator多态空合并运算符
【发布时间】:2023-03-23 06:05:02
【问题描述】:

考虑

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 框架可能会创建一个Results 类型的中间变量(左操作数)。右操作数Result 的类型不同,因此会产生类型转换错误。这个假设正确吗?

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

所以我把代码改成如下样子

return results == null ? new Result() : results;

但是这段代码出错了

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

为什么?我不希望这样,因为这两个实例都符合 IResult。

【问题讨论】:

  • 左操作数的类型是Results,而不是IResult。您需要强制转换才能让编译器理解这一点。

标签: c# .net compiler-errors polymorphism operators


【解决方案1】:

因为:

return results ?? new Result();

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

你需要一个隐式转换。将它投射到IResult,你会没事的:

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

【讨论】:

  • 这是正确答案。替代语法:return (results as IResult) ??新结果();
  • 它不使用您分配给它的变量的类型。这实际上与返回类型无关。即使您将返回类型更改为ResultResults,此表达式仍然无效:results ?? new Result();
  • 正如您所解释的,您可能期望它确实如此。但显然不是。
  • 仅供参考,我对你投了反对票,因为根据规范你错了。编译器不使用第一个操作数的类型。例如这也编译:return results ?? ((IResult)new Result());
  • @Selman22:感谢您告诉我。你是对的。你能验证更新吗?
【解决方案2】:

嗯,这是意料之中的。因为ResultResults 不是同一个类,它们只是实现了一个通用接口,但它们不能相互转换,这就是您收到错误的原因。

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

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

这在C# Specification7.13 The null coalescing operator中也有说明

表达式a ?? b 的类型取决于操作数上可用的隐式转换。按照优先顺序,a ?? b 的类型为A0AB,其中@987654335 @ 是a 的类型(前提是a 有类型),Bb 的类型(前提是b 有类型),如果A 是可空类型,则A0 是A 的底层类型,否则为 A。具体a ?? b处理如下:

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

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

  • 否则,ab不兼容, 并出现编译时错误。

【讨论】:

  • 这可以更好地措辞 - 如果 ResultResults 都被它们各自的类型引用,那么,是的,它们不是兼容的类型。但是,它们都实现了一个通用接口,如果对象由接口类型而不是实现类型引用,则该接口确实使它们兼容。说它们不是“兼容类型”是一种误导。 (编辑:这是关于您在编辑之前的原始帖子
  • 你有两个完整正确的答案,所以我把它标记为答案。
  • C# 可能会添加一个子句,在这种情况下可以应用返回类型推断。
猜你喜欢
  • 2012-09-19
  • 2013-09-13
  • 2015-03-27
  • 2012-09-23
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
相关资源
最近更新 更多