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



有人能解释一下为什么我在以下方法的null合并上出错吗:

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

我不明白的是,为什么第一个返回可以在不需要任何强制转换的情况下工作,而第二个单行null合并则不起作用!

我的目标是ASP.NET Core 2.1


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

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

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

如@Hasan答案的第二次编辑所示,null合并运算符的结果类型是根据操作数类型而不是目标类型解析的。因此,OP的例子失败了,因为ProductNotFoundResult:之间没有隐式转换

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

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

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

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

products.FirstOrDefault(p => p.Id == id) switch { null => NotFound(), var p => p };
[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(产品);。

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

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

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

编辑:

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

2.编辑(此处回答)

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

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

最新更新