Search code examples
c#genericsrepositoryunit-of-work

How to pass a generic type object to a class constructor


I have a generic class that will play the repository role, and I have a second class, this second class should receive an object from the generic repository in the constructor.

Generic class (Repository):

public sealed class Repo<TContext> : IRepo<TContext>, IDisposable where TContext : DbContext, IDbContextFactory<TContext>, new()
{
    #region properties

    /// <summary>
    /// Private DBContext property
    /// </summary>
    private DbContext _Context { get; } = null;

    /// <summary>
    /// Determine if Lazy Loading either activate or not
    /// </summary>
    private bool _LazyLoaded { get; set; }

    #endregion

    #region Construcors

    public Repo(bool LazyLoaded)
    {
        _Context                                  = new TContext();
        _LazyLoaded                               = LazyLoaded;
        _Context.ChangeTracker.LazyLoadingEnabled = LazyLoaded;
    }

    public Repo(DbContext context,bool LazyLoaded)
    {
        _Context                                  = context;
        _LazyLoaded                               = LazyLoaded;
        _Context.ChangeTracker.LazyLoadingEnabled = LazyLoaded;
    }

    public Repo(IConfiguration configuration, string connectionString,bool LazyLoaded)
    {
        _Context                                  = new TContext().GetInstance(configuration, connectionString);
        _LazyLoaded                               = LazyLoaded;
        _Context.ChangeTracker.LazyLoadingEnabled = LazyLoaded;
    }

    #endregion
}

What I tried in my second class :

class UOW:IUOW
{
    public UOW(Repo<DbContext> repo)
    {
        
    }

    public void Commit()
    {

    }

    public void RollBack()
    {

    }
}

But I got these two errors:

CS0311 The type 'Microsoft.EntityFrameworkCore.DbContext' cannot be used as type parameter 'TContext' in the generic type or method 'Repo'. There is no implicit reference conversion from 'Microsoft.EntityFrameworkCore.DbContext' to 'Microsoft.EntityFrameworkCore.IDbContextFactory<Microsoft.EntityFrameworkCore.DbContext>'.

CS0310 'DbContext' 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 'Repo'

Screenshot

How I can configure the constructor of my second class to receive an object from the repo generic class?


Solution

  • There are multiple issues with your code, but to take the error you are concerned with here, DbContext is not a non-abstract type so you cannot use it with the new() generic constraint. It also does not implement IDbContextFactory. There's a couple of things you can do. First would be to make UOW generic and match the same generic constraints, like this:

    class UOW<TContext> : IUOW
        where TContext : DbContext, IDbContextFactory<TContext>, new()
    {
        public UOW(Repo<TContext> repo)
        {
        }
    }
    

    The second is to use a concrete class that does work with all of those constraints, for example:

    class MyContext : DbContext, IDbContextFactory<MyContext>
    {
        public MyContext CreateDbContext()
        {
            throw new NotImplementedException();
        }
    }
    
    class UOW : IUOW
    {
        public UOW(Repo<MyContext> repo)
                     // ^^^^^^^^^ Use the new object here
        {
        }
    }