基类中的构造函数依赖注入

时间:2011-05-26 13:03:26

标签: c# .net dependency-injection inversion-of-control

我正在使用Entity Framework构建存储库基类,其中所有实体存储库都将继承。我想使用Ninject使用Dependency Injection在基类中注入DatabaseContext。我认为构造函数注入是正确的方法,但在派生类I中使用构造函数注入执行此操作必须将参数传递给基类中的构造函数并且我不想要它。因此,Setter Injection更合适吗?

这是我的代码:

public abstract class BaseRepository<TEntity> : IDisposable 
    where TEntity : class
{
    private readonly DatabaseContext _databaseContext;

    protected BaseRepository(DatabaseContext databaseContext)
    {
        this._databaseContext = databaseContext;
    }
}

在上面的例子中使用构造函数注入,在我的派生类中我必须将databaseContext对象传递给基类,我不想对所有派生类执行此操作:< / p>

public class UsuarioRepository : BaseRepository<IUsuario>,
    IUsuarioRepository
{
    public UsuarioRepository(DatabaseContext databaseContext)
        : base(databaseContext)
    {
    }
}

Setter Injection而不是Constructor Injection是解决这个问题的好方法吗?什么是最好的方式?

更新

使用Setter Injection我的派生类不会有构造函数:

public class UsuarioRepository : BaseRepository<IUsuario>, IUsuarioRepository
{
}

我的上下文只是所有应用程序中的一个。我不需要派生类来传递上下文对象,但我喜欢将它注入基类中,以便将来使用模拟测试。

我解决问题:

抱歉,我对此问题感到困惑,但我正在解决构建工厂的问题:

public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity>
   where TEntity : class
{
    private readonly ContextFactory _contextFactory = new ContextFactory();

    protected DatabaseContext CurrentContext
    {
        get
        {
            return this._contextFactory.GetCurrentContext();
        }
    }
 }

我的派生类看起来像这样:

public class UsuarioRepository : BaseRepository<IUsuario>, IUsuarioRepository
{
}

和我的工厂一样:

public class ContextFactory
{
    public DatabaseContext GetCurrentContext()
    {
        return new DatabaseContext();
    }
}

4 个答案:

答案 0 :(得分:17)

Property Injection意味着依赖项是可选的,而Constructor Injection意味着需要依赖项。相应地选择一种模式。

超过95%的情况下,构造函数注入是正确的模式。你不喜欢它怎么样?

答案 1 :(得分:3)

我认为没有“最佳方式”。

构造函数和setter注入并不完全等效,因为setter注入为您提供了更多的灵活性。以下是我在两者之间做出的选择:

假设您创建了一个对象A,并且A需要一个B对象才能工作。要问的问题是:A是否有可能存在/被实例化而没有与之相关的B?它是A对象没有B的有效状态吗?有时A对于有空B没有意义,那么构造函数注入是更好的解决方案。如果,B可以在以后分配给A,而不一定在施工时分配,那么请使用setter注入。所有这些都取决于您尝试建模的域名,答案会因情况而异。

答案 2 :(得分:3)

真的,我看不到将参数传递给基类的任何问题。但如果这是绝对的要求,你可以随时这样做:

public abstract class BaseRepository<TEntity> : IDisposable 
    where TEntity : class
{
    protected BaseRepository()
    {
    }

    protected abstract DatabaseContext GetContext();
}

现在您的派生类可能如下所示:

public class UsuarioRepository : BaseRepository<IUsuario>,
    IUsuarioRepository
{
    private DatabaseContext _databaseContext;

    public UsuarioRepository(DatabaseContext databaseContext)
    {
        _databaseContext = databaseContext;
    }

    protected override DatabaseContext GetContext()
    {
        return _databaseContext;
    }
}

现在,您可以在不将参数传递给基础构造函数的情况下进行构造函数注入。但它真的是一样的。

老实说,我不喜欢setter注入的想法,因为它看起来像DatabaseContext是必需的依赖项。对于必需的依赖项,请执行构造函数注入。如果它是可选的,那么无论如何,继续进行二次注射。

编辑:

由于我们在评论中进行了长时间的对话,因此我对您要完成的工作有了更好的理解。

如果要将派生类与DatabaseContext分离,最好以不同方式设计它。很难将派生类与其基类的依赖关系解耦,如果您认为它们应该被解耦,那么您将有更好的设计根本不使用继承。

public class BaseRepository<TEntity> : IDisposable 
    where TEntity : class
{
    public BaseRepository(DatabaseContext context)
    {
    }
}

现在你的派生类(不再导出)看起来像这样:

public class UsuarioRepository : IUsuarioRepository
{
    public UsuarioRepository(BaseRepository<IUsario> repository)
    {
    }

    // Implement other methods here
}

现在您可以拥有一个使用DatabaseContext的基类,并且派生类不再依赖于它。

答案 3 :(得分:0)

所有这三种方式1.Contstructor,2。Setter和3. Interface Injection各有利弊,取决于使用的情况。如果我会在你的位置,我会选择setter,虽然界面也是一个不错的选择。

请您阅读本文 http://www.devx.com/dotnet/Article/34066