I have a method to update the user status
public async Task UpdateStatus<TService, T>(int id, int status)
where TService : StatusService<T>, new()
{
await new TService().UpdateStatus(id, status);
}
My UserService
have constructor
public class UserService : StatusService<User>
{
public UserService(MyContext context) : base(context)
{
}
....
}
Action to update user status:
public async Task UpdateUserStatus(int id, int status)
{
await UpdateStatus<UserService, User>(id, status);
}
Then my code have the error:
'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
How do I pass the constructor with parameter as generic type?
CodePudding user response:
Your fundamental issue is that you need an instance of MyContext
at the point where you want to create the TService
, as long as you are using a UserService
object.
One way to solve this is to pass in a Func<TService>
to the UpdateStatus()
method instead of specifying the new
restraint:
public async Task UpdateStatus<TService, T>(int id, int status, Func<TService> serviceCreator)
where TService : StatusService<T>
{
await serviceCreator().UpdateStatus(id, status);
}
Then the implementation of UpdateUserStatus()
would look something like this:
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));
}
The issue you then face is how to obtain the MyContext
instance that you need for creating the UserService
object. You can't avoid the need for the MyContext
instance because the UserService
requires it when you create it.
Here's a runnable example on DotNetFiddle.
You can take a further step of injecting a delegate with which to create the MyContext
object:
public async Task UpdateUserStatus(int id, int status, Func<MyContext> contextProvider)
{
await UpdateStatus<UserService, User>(id, status, () => new UserService(contextProvider()));
}
Now we've pushed the MyContext
creation to the outer level. The outer level must still be able to obtain or create a MyContext
, of course.
Here's a runnable example with those changes on DotNetFiddle.
CodePudding user response:
Looks like you're set up to use DI in your project, so you should use it.
In your Program.cs, register your classes that implement your base class (which could be better as an interface), eg:
builder.Services.AddTransient<StatusService<User>, UserService>();
Now instead of having a separate task to update the status, just pass your expected service into your constructor via DI which will automatically include the context:
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);
}
}