Constructor Dependency Injection in Base Class

10,651

Solution 1

Property Injection implies that the dependency is optional, while Constructor Injection implies that the dependency is required. Choose a pattern accordingly.

In more than 95% of the cases Constructor Injection is the correct pattern. What about it don't you like?

Solution 2

I don't think there is a "best way".

Constructor and setter injection are not exactly equivalent, as setter injection provides you a little more flexibility. Here is how I choose between the two:

Lets say you create an object A, and A needs a B object to work. Question to be asked is: Is it possible for A to exist/be instantiated without having a B associated with it? Is it a valid state for the A object to not have a B? Sometimes it does not make sense for A to ever have a null B, then constructor injection is the better solution. If, it is ok for B to be assigned to A later on and not necessarily at construction time, then go with setter injection. All this depends on the domain that you are trying to model, and the answers will change from situation to situation.

Solution 3

Really, I can't see any problem with passing a parameter to a base class. But if that's an absolute requirement, you could always do this:

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

    protected abstract DatabaseContext GetContext();
}

Now your derived classes can look like this:

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

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

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

Now you can have constructor injection without passing a parameter to the base constructor. But it's really the same thing.

I honestly don't like the idea of setter injection, because it looks like the DatabaseContext is a required dependency. For required dependencies, do constructor injection. If it were optional, then by all means, go ahead and do setter injection.

EDIT:

Due to our long conversation in the comments, I have a much better understanding of what you're trying to accomplish.

If you want to decouple your derived classes from the DatabaseContext, you might be better off designing it differently. It is hard to decouple a derived class from its base class's dependencies, and if you think they should be decoupled, then you will have better design not using inheritance at all.

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

Now your derived classes (which would not be derived anymore) would look like this:

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

    // Implement other methods here
}

Now you can have your one base class that uses the DatabaseContext, and your derived classes are no longer dependent on it.

Share:
10,651
Acaz Souza
Author by

Acaz Souza

@acazsouza

Updated on June 04, 2022

Comments

  • Acaz Souza
    Acaz Souza almost 2 years

    i'm building a repository base class with Entity Framework where all Entities repository will inherit. I want to inject the DatabaseContext in base class using Dependency Injection using Ninject. I think the Constructor Injection is the right way, but doing this with Constructor Injection in derived class I will must to pass parameter to constructor in base class and I don't want it. Therefore, a Setter Injection is more appropriate?

    Here's my code:

    public abstract class BaseRepository<TEntity> : IDisposable 
        where TEntity : class
    {
        private readonly DatabaseContext _databaseContext;
    
        protected BaseRepository(DatabaseContext databaseContext)
        {
            this._databaseContext = databaseContext;
        }
    }
    

    Using Constructor Injection in the above example, in my derived class I will must to pass databaseContext object to base class, I don't like to doing this to all my derived class:

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

    Setter Injection instead of Constructor Injection is a good way to solve that? What is the best way?

    Update:

    Using Setter Injection my derived class's will not have constructors:

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

    My Context is only one in all application. I don't need derived class to pass context object, but i like to inject it in base class to using mocks for tests in future.

    I Solve the problem:

    Sorry, I'm confusing with the question, but i'm solving my problem building a Factory:

    public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity>
       where TEntity : class
    {
        private readonly ContextFactory _contextFactory = new ContextFactory();
    
        protected DatabaseContext CurrentContext
        {
            get
            {
                return this._contextFactory.GetCurrentContext();
            }
        }
     }
    

    And my derived class will look like that:

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

    And My Factory like that:

    public class ContextFactory
    {
        public DatabaseContext GetCurrentContext()
        {
            return new DatabaseContext();
        }
    }
    
  • Acaz Souza
    Acaz Souza almost 13 years
    I don't like to pass a parameter to base class in my derived class, using setter injection this will not occur.
  • Acaz Souza
    Acaz Souza almost 13 years
    The question is, I don't like to noise my derived class passing parameter to base class constructors.
  • Morten Mertner
    Morten Mertner almost 13 years
    @Acaz personal preferences aside, constructor injection is really the only appropriate solution for your scenario.
  • Matthew Abbott
    Matthew Abbott almost 13 years
    @Acaz The problem with that is that if BaseRepository<TEntity> requires an instance of DatabaseContext to operate, it is a dependency, and you should not allow an instance of the base class to be instantiated with an invalid state. Constructors are used to create an instance of a type that should be usable. Using setting injection just introduces the need for the developer to know precisely that they need to set the DatabaseContext as an additional step in the type initialisation. Not ideally the best thing for the developer. Simple, if it is a dependency, use constructor injection.
  • Acaz Souza
    Acaz Souza almost 13 years
    But the problem is using Constructor Injection all my derived class will have : base(object) code. I want to use Setter Injection to a required dependency. This post is what I'm talking about: davybrion.com/blog/2009/11/…
  • Acaz Souza
    Acaz Souza almost 13 years
    My context is ONLY ONE of all application! I don't need to derived class to pass context.
  • Acaz Souza
    Acaz Souza almost 13 years
    @Phil Why i will pass parameter to my base class constructor if that parameter is ONLY ONE in all application? Why not pass direct into base class?
  • Phil
    Phil almost 13 years
    @Acaz Because it's a required dependency. The purpose of a constructor is to ensure that all required dependencies are given to the class at construction time - in other words, constructors prevent an object from being able to exist without the correct required dependencies. My question is... why NOT pass a parameter to the base constructor? What's wrong with doing so?
  • Phil
    Phil almost 13 years
    @Acaz I also don't understand something: why is it important that the DatabaseContext is the ONLY ONE in the application? That doesn't have anything to do with passing references to constructors.
  • Acaz Souza
    Acaz Souza almost 13 years
    @Phil Why NOT? Because the DatabaseContext object is ONLY ONE in all application. All derived class is required to use the only DatabaseContext object that there, there's no other. Because that passing DatabaseContext object to base class direct is much more better, i don't need to worry about DatabaseContext object anymore. If I want to replace DatabaseContext object tomorrow, I'll do that in only one place, avoid to change in all derived class. Do you understand?
  • Phil
    Phil almost 13 years
    @Acaz I see. So you are wanting to decouple the derived classes from the DatabaseContext. Correct? Now THAT is a valid reason.
  • Acaz Souza
    Acaz Souza almost 13 years
    @Phil YESSS! And I think the Setter Injection is the best way to do that, but what you think?
  • Phil
    Phil almost 13 years
    @Acaz The problem with inheritance is that it requires derived classes to be tightly coupled to their base classes. You might be better off designing it differently. Instead of inheriting from your base class, perhaps it would be better for the derived classes to just contain a reference to the base class. That would decouple your derived classes from the DatabaseContext.
  • Acaz Souza
    Acaz Souza almost 13 years
    @Phil Do you say creating a interface to my base class and using it in my derived class?
  • Phil
    Phil almost 13 years
    @Acaz Correct. I'll post an update to my answer in a few minutes.
  • Acaz Souza
    Acaz Souza almost 13 years
    @Phil If I build a Interface of BaseRepository and UsuarioRepository inherits from that Interface? I Will edit your post...
  • Phil
    Phil almost 13 years
    The design I suggest may not be the actual design you go with. But the point is, don't inherit from the base class. Just use the base class in your "derived" classes.
  • Acaz Souza
    Acaz Souza almost 13 years
    @Phil there's no way to doing that inheriting from baseclass? Your example don't is util.
  • Phil
    Phil almost 13 years
    You CAN inherit from the base class. But you might have better design if you don't inherit from the base class.
  • Mark Seemann
    Mark Seemann almost 13 years
    @Acaz Souza: Yes, they will need that, because the dependency is required. Since the dependency is required, having the compiler enforce this invariant is a good thing.
  • fearofawhackplanet
    fearofawhackplanet almost 13 years
    +1 this is the way I would go with it, though I think the OP is kinda asking an impossible question. Certainly, using property injection would be a very bad idea.
  • Robert Noack
    Robert Noack almost 9 years
    This is a nice solution, if it works, but it seems really dependent on what DI framework you are using, if it will let you inject the base abstract class without binding any implementation in the container, and if it will be able to call the constructor for the abstract class (if it will call from the context of the injecting class or some static resolver that cant call this method?) Is this tested? And in which frameworks does it work / doesn't it work ?
  • Phil
    Phil almost 9 years
    @RobertNoack I believe you may have found a typo in my answer. The base class was not supposed to be abstract. This really only works if a person ditches the abstract class idea and designs it differently.