“无法确定,因为没有隐式转换”,如果返回,则使用三元

本文关键字:无法确定 三元 返回 因为 转换 如果 | 更新日期: 2023-09-27 18:36:40

我有以下 ASP.NET Web API 2 操作,如果返回三元:

[HttpDelete]
public IHttpActionResult Delete()
{
    bool deleted;
    // ...
    return deleted ? this.Ok() : this.NotFound();
}

我收到一个

无法确定条件表达式的类型,因为存在 "System.Web.Http.Results.OkResult"和"System.Web.Http.Results.OkResult"之间没有隐式转换 'System.Web.Http.Results.NotFoundResult'

当他们都实现IHttpActionResult.

但是,如果我删除三元组,编译器很高兴:

if (deleted)
{
    return this.Ok();
}
return this.NotFound();

这是为什么呢?

“无法确定,因为没有隐式转换”,如果返回,则使用三元

您需要

将结果显式转换为IHttpActionResult

return deleted ? (IHttpActionResult) this.Ok() : this.NotFound();

编辑:

至于格兰特问题:

为什么 Sam 的第二个代码块在没有显式转换为 IHttpActionResult,只是出于好奇?这是特别的吗 到条件 ?: 运算符?

让我们创建一个简单的演示。假设以下代码:

public interface IFoo { }
public class B : IFoo { }
public class C : IFoo { }

然后是以下内容:

public class A
{
    IFoo F(bool b)
    {
        return b ? (IFoo) new B() : new C();
    }
}

让我们看看编译器如何反编译三元运算符:

private IFoo F(bool b)
{
    IFoo arg_13_0;
    if (!b)
    {
        IFoo foo = new C();
        arg_13_0 = foo;
    }
    else
    {
        arg_13_0 = new B();
    }
    return arg_13_0;
}

显式强制转换足以让编译器推断变量应该是 IFoo 类型,从而满足我们的整个if-else。这就是为什么我们只"提示"一次类型转换的编译器就足够了。

@dcastro引用了语言规范中确定类型控制的确切部分,请参阅教科书定义。

在三元表达式A? B : C中,必须有一个引用转换(例如,从基类型到派生类型,反之亦然)从B到C或C到B。

你希望编译器找到两种类型中最派生的共同祖先(即IHttpActionResult ) - 编译器不会这样做。

作为一般经验法则,任何表达式的结果类型都必须包含在表达式本身中。 即,bool? dog : cat不能返回animal,因为没有 animal 类型的变量是表达式的一部分。

从 C# 语言规范第 7.14 节条件运算符:

?: 运算符的第二个和第三个操作数 x 和 y 控制条件表达式的类型。

  • 如果 x 具有类型 X,y 具有 Y 类型,则
      如果存在从 X 到 Y 的隐式转换
    • (§6.1),但不存在从 Y 到 X 的隐式转换,则 Y 是条件表达式的类型
    • 如果存在从 Y 到 X 的隐式转换
    • (§6.1),但不存在从 X 到 Y 的隐式转换,则 X 是 条件表达式。
    • 否则,无法确定表达式类型,并且会发生编译时错误

从 C# 9.0 开始,OP 的示例将成功编译,因为三元条件表达式的结果类型现在基于目标类型。以前,它基于操作数的类型;它们必须相等,或者一个操作数必须隐式转换为另一个操作数。