如何在 ActionResult ASP.NET Core 2.1 中使用空合并运算符

How to use null-coalescing operator with ActionResult ASP.NET Core 2.1

有人可以向我解释为什么我在使用以下方法进行空合并时遇到错误:

private readonly Product[] products = new Product[];

[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
    var product = products.FirstOrDefault(p => p.Id == id);
    if (product == null)
        return NotFound(); // No errors here
    return product; // No errors here

    //I want to replace the above code with this single line
    return products.FirstOrDefault(p => p.Id == id) ?? NotFound(); // Getting an error here: Operator '??' cannot be applied to operands of type 'Product' and 'NotFoundResult'
}  

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
}

我不明白的是为什么第一个 return 不需要任何转换就可以工作,而第二个单行空合并不起作用!

我的目标是 ASP.NET Core 2.1


编辑: 感谢 and 的解释,但我不建议在这里使用 null 合并,因为 NotFound() 不会 return 转换后的正确错误代码!

return (ActionResult<Product>)products?.FirstOrDefault(p => p.Id == id) ?? NotFound();

由于无法转换类型而发生错误。

试试这个:

[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
    var result = products?.FirstOrDefault(p => p.Id == id);
    return result != null ? new ActionResult<Product>(result) : NotFound();
}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public ActionResult<Product> GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return product;
}

In the preceding code, a 404 status code is returned when the product doesn't exist in the database. If the product does exist, the corresponding Product object is returned. Before ASP.NET Core 2.1, the return product; line would have been return Ok(product);.

从上面的代码和微软相关page的解释可以看出,在.NET Core 2.1之后你不需要return控制器中的确切类型(ActionResult<T> ) 就像之前一样。要使用该功能,您需要添加属性以指示可能的响应类型,例如 [ProducesResponseType(200)] 等。

在您的情况下,您需要做的基本上是向您的控制器方法添加适当的响应类型属性,如下所示(因为您使用 .NET Core 2.1 进行开发)。

[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public ActionResult<Product> GetById(int id)

编辑:

无法编译程序(使用空合并运算符)的原因是 return 类型不兼容。在一种情况下它 return 乘积 class,否则它 return 乘积 ActionResult<T>。按照我的建议更新代码后,我想您将能够使用空合并运算符。

2。编辑 (在这里回答)

在更深入地挖掘问题之后,我发现当使用三元 if 语句或 null 合并运算符时,我们需要明确指定我们希望从该语句生成的类型,当多个类型可能是 return编辑。如前所述 ,编译器不会在不隐式转换的情况下决定它 return 是哪种类型。因此,将 return 类型转换为 ActionResult 即可解决问题。

return (ActionResult<Product>) products.FirstOrDefault(p=>p.id ==id) ?? NotFound();

但是最好像上面那样添加响应类型属性。

OP 的问题可以分为两部分:1) 为什么建议的空合并表达式无法编译,以及 2) 是否有另一种简洁(“单行”)方式 return 结果在 ASP.NET 核心 2.1 中?

如@Hasan 的回答的第二次编辑所示,null-coalescing operator 的结果类型是根据操作数类型而不是目标类型来解析的。因此,OP 的示例失败了,因为 ProductNotFoundResult:

之间没有隐式转换
products.FirstOrDefault(p => p.Id == id) ?? NotFound();

@Kirk Larkin 在评论中提到了一种修复它的方法,同时保持简洁的语法:

products.FirstOrDefault(p => p.Id == id) ?? (ActionResult<Product>)NotFound();

从 C# 8.0 开始,您还可以使用 switch expression:

products.FirstOrDefault(p => p.Id == id) switch { null => NotFound(), var p => p };