在需要时从接口转换到某个具体类是一个好习惯吗?

Ewe*_*ton 1 c# oop design-patterns dependency-injection simple-injector

我正在开发一个小系统,我开发了经典的通用存储库。现在,我的 DAL 具有以下架构。

public interface IRepositorio<T> where T : class
{
    T Get(long id);
    long Insert(T obj);
    bool Update(T obj);
    bool Delete(T obj);
}

public abstract class Repositorio<T> : IRepositorio<T> where T : class
{
    public IDbConnection Connection
    {
        get
        {
            return new SqlConnection(ConfigurationManager.ConnectionStrings["DBFila"].ConnectionString);
        }
    }

    public T Get(long id)
    {
        //...
    }

    public long Insert(T obj)
    {
        //...
    }

    public bool Update(T obj)
    {
        //...
    }

    public bool Delete(T obj)
    {
        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

我的具体存储库如下所示:

public class FilaRepositorio : Repositorio<FilaRepositorio>
{
    public FilaRepositorio() 
    {
    }

    public void SomeCustomMethod()
    {
        // Some custom method
    }
}
Run Code Online (Sandbox Code Playgroud)

我也使用 Simple Injector 来遵循 IoC 和 DI 模式,因此,当我尝试调用“SomeCustomMethod()”时,我无法访问它(显然)。看:

public class Processador
{
    private IRepositorio<FilaModel> _repoFila;
    public Processador(IRepositorio<FilaModel> repoFila)
    {
        _repoFila = repoFila;
    }

    public void Processar()
    {
        _repoFila.SomeCustomMethod(); // <-- wrong

        ((FilaRepositorio)_repoFila).SomeCustomMethod();// <-- works
    }
}
Run Code Online (Sandbox Code Playgroud)

鉴于此,我有一些问题:

  • 制作该演员表(FilaRepositorio)是一种好的或可接受的做法吗?
  • 如果这不是一个好的做法,如何为这种情况编写好的代码?

Nko*_*osi 5

有几个选项可用。制作演员表的主要问题是它是一个实现问题。

如果注入的对象不是 a 会发生什么FilaRepositorio

通过进行强制转换,您将类与不能保证是注入依赖项的实现问题紧密耦合。因此,构造函数对于执行其功能所需的内容并不完全真实。

这表明需要实践显式依赖原则

显式依赖原则指出:

方法和类应该明确要求(通常通过方法参数或构造函数参数)它们需要的任何协作对象才能正常运行。

避免它的一种方法是创建一个派生接口,显式公开其依赖项的所需功能。

public interface IFilaRepositorio : IRepositorio<FilaModel> {
    void SomeCustomMethod();
}

public class FilaRepositorio : Repositorio<FilaModel>, IFilaRepositorio {
    public void SomeCustomMethod() {
        //...other code removed for brevity.
    }
}
Run Code Online (Sandbox Code Playgroud)

Processador依赖于更有针对性的抽象。

现在根本不需要演员表,类明确表达了它需要什么。

public class Processador {
    private readonly IFilaRepositorio _repoFila;

    public Processador(IFilaRepositorio  repoFila) {
        _repoFila = repoFila;
    }

    public void Processar() {
        _repoFila.SomeCustomMethod(); // <-- works
    }
}
Run Code Online (Sandbox Code Playgroud)