Using "Generics" to implement "Unit Of Work" I need to design a generic &quot;Unit Of Work&quot;, basically so that I can &quot;change the context of the Database&quot; only changing the implementation of IUnitOfWork on my DI container. I will exemplify below.
So far, I have following solution:
IUnitOfWork.cs
public interface IUnitOfWork
{
    TTransactionType GetCurrentTransaction&lt;TTransactionType&gt;();

    Task CommitAsync(CancellationToken cancellationToken);
    Task BeginTransactionAsync(CancellationToken cancellationToken);
}

UnitOfWorkMongoDB.cs
public class UnitOfWorkMongoDB : IUnitOfWork
{
    IClientSessionHandle _session;
    readonly IMongoDbContext _mongoDbContext;

    public UOLMongoDB(IMongoDbContext mongoDbContext)
    {
        _mongoDbContext = mongoDbContext;
    }

    public TTransactionType GetCurrentTransaction&lt;TTransactionType&gt;() =&gt; (TTransactionType)_session;

    public async Task CommitAsync(CancellationToken cancellationToken)
    {
        await _session.CommitTransactionAsync();
    }

    public async Task BeginTransactionAsync(CancellationToken cancellationToken)
    {
        _session = await _mongoDbContext.MongoClient.StartSessionAsync(cancellationToken: cancellationToken);
        _session.StartTransaction();
    }
}

DI Resolution
 services.AddScoped&lt;IUnitOfWork, UnitOfWorkMongoDB&gt;();

Using the solution
public class MyServiceA
{
    public MyServiceA(IUnitOfWork unitOfWork)
    {
        /*...*/
    }
}

public class MyServiceB
{
    public MyService(IUnitOfWork unitOfWork)
    {
        /*...*/
    }
}

Considerations

The IUnitOfWork interface is not really generic, the only
&quot;generic thing&quot; used, was TTransactionType, since each Database
driver manufacturer has a different implementation of transaction
handling. Like:

MongoDB = IClientSessionHandler.cs
MySql = MySqlTransaction.cs
Oracle = OracleTransaction.cs


The IUnitOfWork interface is non generic in attempt to avoid refactoring
code when we change his implementation on D.I resolution.


Samples with non generic IUnitOfWork:
 services.AddScoped&lt;IUnitOfWork, UnitOfWorkPostgreSQL&gt;(); //OR
 services.AddScoped&lt;IUnitOfWork, UnitOfWorkOracle&gt;(); //OR
 services.AddScoped&lt;IUnitOfWork, UnitOfWorkMySQL&gt;(); //OR

Dependencies not break:
public class MyServiceA
{
    public MyServiceA(IUnitOfWork unitOfWork)
    {
        /*...*/
    }
}


&quot;Problems&quot; with with a generic IUnitOfWork&lt;TUnitOfWork&gt;.

If we change the resolution on D.I, all services dependecies will break, like:
services.AddScoped&lt;IUnitOfWork&lt;UnitOfWorkPostgreSQL&gt;, UnitOfWorkPostgreSQL&gt;();

On MyServiceB.cs for example, before he depends of IUnitOfWork&lt;UnitOfWorkMongoDB&gt; and now, my D.I container not solves it. This can cause several changes on application code base.
public class MyServiceB
{
    public MyServiceB(IUnitOfWork&lt;UnitOfWorkMongoDB&gt; unitOfWork)
    {
        /*...*/
    }
} 

I still feel uncomfortable with the explicit conversion (TTransactionType)_session; on GetCurrentTransaction&lt;TTransactionType&gt;() method, is there any other approach to make this method? Or am I worrying too much?
What do you think can be improved in this solution? Any evaluation/improvement is welcome!
P.S I created a little repo with this implementation here.
Trying to not promote low-level transaction implementation in initial design,
IDbContext is the place for db-transactions.
 public interface IDbContext 
 {
      void Commit();
      void Rollback();   
 } 


Using “Generics” to implement “Unit Of Work”

public interface IUnitOfWork&lt;T&gt; where T: IDbContext
{
   T DbContext { get; }
}

Now the async version of IUnitOfWork
public interface IAsyncUnitOfWork: IUnitOfWork&lt;IDbContext&gt; 
{     
    Task CommitAsync(CancellationToken cancellationToken);
    Task BeginTransactionAsync(CancellationToken cancellationToken);
}

Trying to implement abstract system with our setup.
public abstract class AbstractUnitOfWork: IAsyncUnitOfWork 
{
  public abstract IDbContext DbContext {get; set; }
  
  public AbstractUnitOfWork(IDbContext context)
  {
    DbContext = context;
  }
  
  public abstract Task BeginTransactionAsync(CancellationToken cancellationToken);
  public abstract Task CommitAsync(CancellationToken cancellationToken);
}