2

有人可以解释一下为什么我在以下方法的 null-coalescing 上遇到错误:

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; }
}

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

我的目标是 ASP.NET Core 2.1


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

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

4

3 回答 3

2

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

正如@Hasan 回答的第二次编辑中所指出的,空合并运算符的结果类型是根据操作数类型而不是目标类型来解析的。Product因此,OP 的示例失败了,因为and之间没有隐式转换NotFoundResult

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

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

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

从 C# 8.0 开始,您还可以使用switch 表达式

products.FirstOrDefault(p => p.Id == id) switch { null => NotFound(), var p => p };
于 2021-11-15T17:20:12.970 回答
1

发生错误是因为无法转换类型。

尝试这个:

[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
    var result = products?.FirstOrDefault(p => p.Id == id);
    return result != null ? new ActionResult<Product>(result) : NotFound();
}
于 2019-02-04T13:06:35.823 回答
1
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public ActionResult<Product> GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return product;
}

在上述代码中,当产品在数据库中不存在时,会返回 404 状态码。如果产品确实存在,则返回相应的 Product 对象。ASP.NET Core 2.1之前,返回产品;行将是返回 Ok(product);。

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

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

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

编辑:

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

2.编辑 (在这里回答)

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

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

但最好添加响应类型属性,如上所示。

于 2019-02-04T13:11:29.873 回答