在.NET Core上传递参数为泛型的构造函数



我的控制器在mvc中更新用户状态的操作:

public class UserController : AdminController
{
public async Task UpdateUserStatus(int id, int status)
{
await UpdateTheStatus<UserService, User>(id, status);
}
}

我有一个基本控制器来更新用户状态

public abstract class AdminController : ControllerBase
{
public async Task UpdateTheStatus<TService, T>(int id, int status)
where TService : StatusService<T>, new()
{
await new TService().UpdateStatus(id, status);
}
}

我的UserService.cs具有构造函数

public class UserService : StatusService<User>
{
public UserService(MyContext context) : base(context)
{
}
....
}

基类StatusService.cs

public abstract class StatusService<T>
{
protected MyContext ctx = null;
public StatusService(MyContext context)
{
ctx = context;
}
public async virtual Task UpdateStatus(int id, int status)
{ 
...
await ctx.SaveChangesAsync();
}
}

然后我的代码出现错误:

'UserService' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TService' in the generic type or method

如何将参数作为泛型类型传递给构造函数?

您的基本问题是,只要您使用的是UserService对象,就需要在要创建TService的位置上创建MyContext的实例。

解决此问题的一种方法是将Func<TService>传递给UpdateStatus()方法,而不是指定new约束:

public async Task UpdateStatus<TService, T>(int id, int status, Func<TService> serviceCreator)
where TService : StatusService<T>
{
await serviceCreator().UpdateStatus(id, status);
}

那么UpdateUserStatus()的实现看起来是这样的:

public async Task UpdateUserStatus(int id, int status)
{
var context = new MyContext(); // However you obtain this.
await UpdateStatus<UserService, User>(id, status, () => new UserService(context));
}

然后面临的问题是如何获得创建UserService对象所需的MyContext实例。您无法避免对MyContext实例的需要,因为UserService在创建它时需要它。

下面是一个关于DotNetFiddle的可运行示例。

您可以进一步注入用于创建MyContext对象的委托:

public async Task UpdateUserStatus(int id, int status, Func<MyContext> contextProvider)
{
await UpdateStatus<UserService, User>(id, status, () => new UserService(contextProvider()));
}

现在,我们已经将MyContext的创建推向了外部级别。当然,外部级别必须仍然能够获得或创建MyContext

下面是一个在DotNetFiddle上进行这些更改的可运行示例。

看起来你已经设置好在项目中使用DI,所以你应该使用它。

在Program.cs中,注册实现基类的类(作为接口可能会更好(,例如:

builder.Services.AddTransient<StatusService<User>, UserService>();

现在,不需要单独的任务来更新状态,只需通过DI将您期望的服务传递到构造函数中,DI将自动包括上下文:

public class WhatIsYourClassCalled
{
private readonly StatusService<User> _statusService;
public WhatIsYourClassCalled(StatusService<User> statusService)
{
_statusService = statusService;
}
public async Task UpdateUserStatus(int id, int status)
{
await _statusService.UpdateStatus(id, status);
}
}

最新更新