如何定义一个包含基类的方法以及当前类中的方法的接口?

问题描述 投票:0回答:1

我有一个包含常见 CRUD 功能的基类:

public class GeneralRepository<T> : IGeneralRepository<T>
{
    private readonly IConfiguration _config;
    private readonly string _tableName;

    public GeneralRepository(IConfiguration config, string tableName)
    {
        _config = config;
        _tableName = tableName;
    }

    public async virtual Task<OperationResult<T>> InsertModelAndReturnAsync(string storedProcedure, T parameters)
    {
        using IDbConnection connection = new SqlConnection(_config.GetConnectionString("Default"));

        try
        {
            var result = await connection.QueryFirstOrDefaultAsync<T>(storedProcedure, parameters, commandType: CommandType.StoredProcedure);
            if (result != null)
            {
                return OperationResult<T>.Success(result);
            }
            else
            {
                return OperationResult<T>.Failure("No records created.");
            }
        }
        catch (Exception ex)
        {
            return OperationResult<T>.Failure($"An error has occured: {ex.Message}");
        }
    }

    public async virtual Task<OperationResult<T>> DeleteModelAndReturnAsync(string storedProcedure, int id)
    {
        using IDbConnection connection = new SqlConnection(_config.GetConnectionString("Default"));

        try
        {
            var result = await connection.QueryFirstOrDefaultAsync<T>(storedProcedure, new { Id = id }, commandType: CommandType.StoredProcedure);
            if (result != null)
            {
                return OperationResult<T>.Success(result);
            }
            else
            {
                return OperationResult<T>.Failure("No records deleted.");
            }
        }
        catch (Exception ex)
        {
            return OperationResult<T>.Failure($"An error has occured: {ex.Message}");
        }
    }

    public async virtual Task<OperationResult<T>> UpdateModelAndReturnAsync(string storedProcedure, T parameters)
    {
        using IDbConnection connection = new SqlConnection(_config.GetConnectionString("Default"));

        try
        {
            var result = await connection.QueryFirstAsync<T>(storedProcedure, parameters, commandType: CommandType.StoredProcedure);

            return OperationResult<T>.Success(result);
        }
        catch (Exception ex)
        {
            return OperationResult<T>.Failure($"An error has occured: {ex.Message}");
        }
    }

    public async virtual Task<ICollection<T>> GetAllAsync()
    {
        try
        {
            using IDbConnection connection = new SqlConnection(_config.GetConnectionString("Default"));

            var parameters = new { TableName = _tableName };

            var query = """
                SELECT *
                FROM @TableName
                """;

            var result = (await connection.QueryAsync<T>(query, parameters)).ToList();

            return result;
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    public async virtual Task<T?> GetByIdAsync(int id)
    {
        try
        {
            using IDbConnection connection = new SqlConnection(_config.GetConnectionString("Default"));

            var parameters = new { TableName = _tableName, Id = id };

            var query = """
                SELECT *
                FROM @TableName
                WHERE Id = @Id
                """;

            T? result = await connection.QueryFirstOrDefaultAsync<T>(query, parameters);

            return result;
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

具有以下界面:

public interface IGeneralRepository<T>
{
    Task<OperationResult<T>> DeleteModelAndReturnAsync(string storedProcedure, int id);
    Task<ICollection<T>> GetAllAsync();
    Task<T?> GetByIdAsync(int id);
    Task<OperationResult<T>> InsertModelAndReturnAsync(string storedProcedure, T parameters);
    Task<OperationResult<T>> UpdateModelAndReturnAsync(string storedProcedure, T parameters);
}

然后,我有一个存储库来执行更多特定于表的查询:

public class LoginRepository : GeneralRepository<LoginModel>, ILoginRepository
{
    private readonly IConfiguration _config;
    public const string TableName = "Login";
    public LoginRepository(IConfiguration config) : base(config, TableName)
    {
        _config = config;
    }

    public Task Test()
    {         
        throw new NotImplementedException();
    }
}

我将

ILoginRepository
定义如下:

public interface ILoginRepository : IGeneralRepository<LoginModel>
{
    Task Test();
}

我遇到的问题是我收到一条错误,指出

LoginRepository
不履行
IGeneralRepository<LoginModel>
中定义的合同。

Severity    Code    Description Project File    Line    Suppression State
Error   CS0738  'LoginRepository' does not implement interface member 'IGeneralRepository<LoginModel>.DeleteModelAndReturnAsync(string, int)'. 'GeneralRepository<LoginModel>.DeleteModelAndReturnAsync(string, int)' cannot implement 'IGeneralRepository<LoginModel>.DeleteModelAndReturnAsync(string, int)' because it does not have the matching return type of 'Task<OperationResult<LoginModel>>'.

我认为既然我继承了

GeneralRepository
的方法,那么这个契约就会得到履行。

我需要一个接口来访问当前类以及父类的方法,因为我正在尝试将此存储库签入 DI:

builder.Services.AddScoped<ILoginRepository, LoginRepository>();

如果我将

ILoginRepository
定义为:

public interface ILoginRepository
{
    Task Test();
}

我的代码可以工作,但现在我无法访问依赖注入中的基类方法。

c# oop design-patterns dependency-injection
1个回答
0
投票

使用这个设计比较好:

public class GeneralRepository<T> 
{        
    public GeneralRepository(IConfiguration config, string tableName)
    {
       // connection details           
    }

    // implementation of a general repository     
    public Task Update(T model)
    {         
        ...
    }
}


public class LoginRepository : GeneralRepository<LoginModel>, ILoginRepository
{
    private readonly IConfiguration _config;
    public const string TableName = "Login";
    public LoginRepository(IConfiguration config) : base(config, TableName)
    {
        _config = config;
    }  
    
    public Task Test()
    {         
        throw new NotImplementedException();
    }
}

public interface ILoginRepository
{
    Task Update(LoginModel model);
    Task Test();
}

这样:

  • 您可以重用 GeneralRepository 方法,而不会暴露其中不需要的方法。事实上,您的特定存储库接口决定公开什么。
  • 您的设计符合接口隔离原则。
  • IGeneralRepository 是不必要的(因为它不应该是)并从设计中删除。
© www.soinside.com 2019 - 2024. All rights reserved.