C# 具有可选泛型参数的泛型和可重写控制器方法

C# 具有可选泛型参数的泛型和可重写控制器方法,c#,asp.net-core,C#,Asp.net Core,我有以下通用控制器: public abstract class ControllerBase<TEntity, TEntityDto> { public async Task<ActionResult<IEnumerable<TEntityDto>>> GetAll() { ... } } 公共抽象类ControllerBase { 公共异步任务GetAll() { ... } } 我需要能够根据与通用

我有以下通用控制器:

public abstract class ControllerBase<TEntity, TEntityDto>
{
    public async Task<ActionResult<IEnumerable<TEntityDto>>> GetAll()
    {
        ...
    }
}
公共抽象类ControllerBase
{
公共异步任务GetAll()
{
...
}
}
我需要能够根据与通用控制器(返回所有实体)相同的路由上的查询参数筛选实体。因此,我的想法是覆盖通用控制器并将其重写为:

public abstract class ControllerBase<TEntity, TEntityDto, TQueryParams>
{
    [HttpGet]
    [ProducesResponseType(200)]
    public async Task<ActionResult<IEnumerable<TEntityDto>>> GetAll(TQueryParams? queryParams)
    {
        // Notice the service layer method is called without parameters in the generic controller
        var instances = await _service.GetAll();

        return Ok(instances);
    }
}
公共抽象类ControllerBase
{
[HttpGet]
[产品响应类型(200)]
公共异步任务GetAll(TQueryParams?queryParams)
{
//请注意,在通用控制器中调用服务层方法时没有参数
var instances=await_service.GetAll();
返回Ok(实例);
}
}
公共类DogsController:EntityController数据库
{
[HttpGet]
[产品响应类型(200)]
公共异步任务GetAll(DogQueryParams queryParams)
{
var实例=wait_service.ListDogs(queryParams.kennel,queryParams.birthYear);
返回Ok(实例);
}
}
但是,我得到了一个错误:
只有不可为null的值类型可以作为'System.nullable'的底层。

我是否使用了正确的方法?


实现预期行为的正确方法是什么?(当我需要根据可选查询参数筛选输出时,它能够覆盖基本控制器方法
GetAll

编译器错误告诉您“只能将不可为空的标记为可为空。”

引用类型本质上是可以为空的。事实上,只有使用C#8.0,我们才能获得对不可为空引用类型的支持。使用编译器开关,因为使用它作为默认值会有问题

结构本身是不可为空的。可空语法最初是为他们发明的。有了C#8.0,它将得到它的第一次扩展,afaik

由于没有通过where子句限制
TQueryParams
,编译器只能假定同时应用于结构类的内容。对于泛型,它总是使用“最小公分母”


但请注意,即使C#8.0支持不可为空的引用类型,据我所知,MSIL实现是如此不同,您无法互换使用它们。您仍然需要决定类或结构是否使用可为null的语法。

您只能将其标记为可为null,因为它还不可为null。隐式地,所有引用类型本质上都可以为空。而且这并不局限于只接受结构或类似的东西,即使在C#8.0中,默认情况下也不会启用不可为null的引用类型。他们仍然需要一个开关。即使如此,它们在MSIL中的差异也太大,无法用于泛型。不要尝试编写泛型代码。这不是最好的商业目的,因为一切都是可变的。改变你的心态。让我们尝试使用CQR。看看这个@kogoia,所以你建议我不要使用通用控制器,只为每个域模型编写
GetAll
控制器?我希望得到一些指导,因为我以前没有在大型项目中使用过C(来自golang/python)。所以你是说,如果我删除
/
可空的
,它应该已经可以工作了。我的问题不是常见的吗?我使用的方法正确吗?@elliott:或者从
TQueryParams中删除问号?查询参数
。或限制
,其中TQueryParams:struct
。两者都可能产生不必要的影响我真的不能告诉你这是否是一件普通的事情,因为我对MVC不太了解。
public class DogsController : EntityControllerBase<Dog,DogDto>
{
    [HttpGet]
    [ProducesResponseType(200)]
    public async Task<ActionResult<IEnumerable<DogDto>>> GetAll(DogQueryParams queryParams)
        {
            var instances = await _service.ListDogs(queryParams.kennel, queryParams.birthYear);
            return Ok(instances);
        }
}