从通用类继承 [英] Inherit from generic class

查看:98
本文介绍了从通用类继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有.net core 2.1项目.还有我的存储库类,如下所示.但是由于MyDbContext构造函数具有参数,因此出现如下错误.当我删除JwtHelper参数时,它运行良好. 但是,我需要在MyDbContext.cs中添加JwtHelper来记录审核.如何实现这一目标?

I have .net core 2.1 project. And my repository classes like below. But because of MyDbContext constructor has parameter, I'm getting error like below. When I remove JwtHelper parametrer, it is working perfectly. But, I need adding JwtHelper in MyDbContext.cs for logging auditings. How can I achieve this?

"MyDbContext"必须是具有公共无参数构造函数的非抽象类型,以便在通用类型或方法"UnitOfWork"中将其用作参数"TContext"

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

UnitOfWork.cs

public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext, new()
{ 
    protected readonly DbContext DataContext;

    public UnitOfWork()
    {
        DataContext = new TContext();
    }

    public virtual async Task<int> CompleteAsync()
    {
        return await DataContext.SaveChangesAsync();
    }

    public void Dispose()
    {
        DataContext?.Dispose();
    }
}

IUnitOfWork.cs

public interface IUnitOfWork<U> where U : DbContext
{ 
    Task<int> CompleteAsync();
}

MyRepos.cs

public class MyRepos : UnitOfWork<MyDbContext>, IMyRepos
{
    private IUserRepository userRepo;
    public IUserRepository UserRepo { get { return userRepo ?? (userRepo = new UserRepository(DataContext)); } }
}

IMyRepos.cs

public interface IMyRepos : IUnitOfWork<MyDbContext>
{
  IUserRepository UserRepo { get; }
}

MyDbContext.cs

public class MyDbContext : DbContext
{
    private readonly IJwtHelper jwtHelper;

    public MyDbContext(IJwtHelper jwtHelper) : base()
    {
        this.jwtHelper= jwtHelper;
    }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        var userId=jwtHelper.GetUserId();
        SaveAudits(userId,base.ChangeTracker);
        return (await base.SaveChangesAsync(true, cancellationToken));
    }
}

UserRepository.cs

public class UserRepository : Repository<User>, IUserRepository
{
    private readonly MyDbContext_context;

    public UserRepository(DbContext context) : base(context)
    {
        _context = _context ?? (MyDbContext)context;
    }
}

IUserRepository.cs

public interface IUserRepository : IRepository<User>
{ }

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IJwtHelper, JwtHelper>();
    services.AddScoped<DbContext, MyDbContext>();
    services.AddTransient<IMyRepos, MyRepos>();
}

推荐答案

问题出在UnitOfWork的构造函数中:

The problem is in the constructor of your UnitOfWork:

public UnitOfWork()
{
    DataContext = new TContext();
}

在这里,您使用默认构造函数构造了类MyDbContext的新对象,但是MyDbContext没有默认构造函数.

Here you construct a new object of class MyDbContext using a default constructor, but MyDbContext does not have a default constructor.

您决定使UnitOfWork非常通用.太好了,因为这使您可以将我们的UnitOfWork与所有DbContexts一起使用.您告诉UnitOfWork的唯一限制是DbContext应该具有默认构造函数.

You decided to make your UnitOfWork very generic. That is great, because this enables you to use our UnitOfWork with all kinds of DbContexts. The only limitation you told your UnitOfWork is that your DbContext should have a default constructor.

一个好的方法是自己创建工厂并将其传递给UnitOfWork.

A good method would be to create the factory yourself and pass it to the UnitOfWork.

如果您不希望或不能给MyDbContext一个默认的构造函数,请考虑告诉您的UnitOfWork它如何创建一个构造函数:嘿,工作单元,如果您需要创建我想要的DbContext,您使用,请使用此功能"

If you don't want, or can't give MyDbContext a default constructor, consider telling your UnitOfWork how it can create one: "Hey unit of work, if you need to create the DbContext that I want you to use, use this function"

实际上,您将使用工厂设计模式

步骤1:使用函数Create()创建一个类,该类将完全创建您要使用的DbContext.

Step 1: Create a class, with a function Create(), that will create exactly the DbContext that you want to use.

interface IDbContextFactory<TContext>
   where TContext : DbContext
{
    DbContext Create();
}

// The MyDbContextFactory is a factory that upon request will create one MyDbcontext object
// passing the JwtHelper in the constructor of MyDbContext
class MyDbContextFactory : IDbContextFactory<MyDbContext>
{
      public IJwthHelper JwtHelper {get; set;}

      public MyDbContext Create()
      {
           return new MyDbContext(this.JwtHelper);
      }


      DbContext IDbContextFactory<HsysDbContext>.Create()
      {
           throw new NotImplementedException();
      }
  }

第2步:告诉您的UnitOfWork如何创建DbContext.

Step 2: tell your UnitOfWork how it should create the DbContext.

public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext 
{ 
    public static IDbContextFactory<TContext> DbContextFactory {get; set;}
    protected readonly DbContext DataContext;

    public UnitOfWork()
    {
        this.DataContext = dbContextFactory.Create();
    }
    ...
}

public void ConfigureServices(IServiceCollection services)
{
    // create a factory that creates MyDbContexts, with a specific JwtHelper
    IJwtHelper jwtHelper = ...
    var factory = new MyDbContextFactory
    {
         JwtHelper = jwtHelper,
    }

    // Tell the UnitOfWork class that whenever it has to create a MyDbContext
    // it should use this factory
    UnitOfWork<MyDbContext>.DbContextFactory = factory;

    ... // etc
}

从现在开始,每当构造UnitOfWork<MyDbContext>对象时, 使用默认构造函数,该构造函数将命令工厂创建一个新的MyDbContext.

From now on, whenever a UnitOfWork<MyDbContext> object is constructed, using the default constructor, this constructor will order the factory to create a new MyDbContext.

您实际上不必实现接口.您的UnitOfWork只需要知道如何创建DbContext.

You don't really have to implement an interface. All that your UnitOfWork needs to know is how to create a DbContext.

您可以通过Func代替接口:

Instead of an interface, you could pass it a Func:

public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext 
{ 
    // use this function to create a DbContext:
    public static Func<TContext> CreateDbContextFunction {get; set;}
    protected readonly DbContext DataContext;

    public UnitOfWork()
    {
        // call the CreateDbContextFunction. It will create a fresh DbContext for you:
        this.DataContext = CreateDbContextFunction();
    }
}

public void ConfigureServices(IServiceCollection services)
{
    // create a factory that creates MyDbContexts, with a specific JwtHelper
    IJwtHelper jwtHelper = ...
    var factory = new MyDbContextFactory
    {
         JwtHelper = jwtHelper,
    }

    // Tell the UnitOfWork class that whenever it has to create a MyDbContext
    // it should use this factory


    UnitOfWork<MyDbContext>.CreateDbContextFunction = () => factory.Create();

在评论后添加

最后一条语句中的() => factory.Create();部分称为lambda表达式.这意味着:创建一个没有输入参数(即()部分)和等于factory.Create()的双精度返回值的函数.

The part: () => factory.Create(); in the last statement is called a lambda expression. It means: create a function without input parameters (that is the () part) and a double return value equal to factory.Create().

类似地,如果您需要创建一个lambda表达式来表示一个带有输入参数Rectangle的函数,并作为输出矩形的表面,则该

Similarly if you need to create a lambda expression that represents a function with input parameter a Rectangle and as output the surface of the rectangle:

Func<Rectangle, double> myFunc = (rectangle) => rectangle.X * rectangle.Y;

换句话说:myFunc是一个函数,具有Rectangle作为输入,而double是输出.功能类似于:

In words: myFunc is a function that has a Rectangle as input, and a double as output. The function is like:

double MyFunc (Rectangle rectangle)
{
    return rectangle.X * rectangle.Y;
}

您这样称呼:

Func<Rectangle, double> calcSurface = (rectangle) => rectangle.X * rectangle.Y;
Rectangle r = ...;
double surface = calcSurface(r);

同样,一个lambda表达式表示一个具有两个输入参数和一个输出参数的函数:

Similarly, a lambda expression that represents a function with two input parameters and one output parameter:

Func<double, double, Rectangle> createRectangle = 
    (width, height) => new Rectangle {Width = width, Height = height};

Func的最后一个参数<...,...,...,x>始终是返回值

The last parameter of Func<..., ..., ..., x> is always the return value

出于完整性考虑:具有空返回值的方法称为Action:

And for completeness: a method with a void return is called an Action:

Action(Rectangle) displayRectangle = (r) => this.Form.DrawRectangle(r);

这篇关于从通用类继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆