Implicitly injecting dependency in Base class while derived class is resolved through Unity
Asked Answered
V

3

13

I have a base Class Base having dependecy Dep and default and Injection Constructor-

Class Base : IBase
 {

    public IDep Dep { get; set; }

    public Base()
    {
        Console.WriteLine("Default Constructor Base ");
    }

    [InjectionConstructor]
    public Base(IDep dep)
    {
        Console.WriteLine("Injection Constructor Base ");
        Dep = dep;            
    }
}

I thought that Dependency dep should get injected automatically(through Constructor Injection) when derived class is resolved.

But this doesnt seem to work when I derive a class from it and Resolve that class, Instead a default Constructor of Base being called.

I can only get this to work when I explicitly call the constructor from the Derived Class.

class Derived : Base
{

    public Derived ()
    {
        Console.WriteLine("Default Constructor Derived ");
    }

    public Derived (IDep dep) : base(dep1)
    {
        Console.WriteLine("Injection Constructor Derived ");            
    }
}

Does unity provide any direct way to implicitly call the injection Constructor of base class (not by explicit Construtor call)? If not, Is there any reason that why unity container is not doing by itself??

Visional answered 11/9, 2014 at 5:30 Comment(5)
Your problems are caused by having multiple constructors. Your services should only have one single constructor. Having multiple constructors is an anti-pattern and it should be avoided.Suppositive
@Suppositive I got your point that multiple constructors is an anti-pattern. But removing the Default constructor does not resolve the purpose here.Visional
I think it actually resolves your problems, because if both Base and Derived contain each just one constructor that takes in the required dependencies, the problem wont exist at all. I do agree however with @BatteryBackupUnit that having a base class might not be the best design.Suppositive
@Suppositive Should we always include a default constructor in the class . I cannot have a Parametrized Constructor without defining a Default Constructor.Visional
@Suppositive Even if i skip the Default Constructor in the base class my derived class constructor will give the compiler error.Visional
H
19

No, unity is unable to do so. Actually, there's not a single container who can do so. A constructor is there to instantiate a class. If you call two constructors, you'll end up with two instances. If the base class is abstract, you couldn't even call its constructor (except derived constructors as you know).

So by limitations of C#.net, if you want to use constructor injection, it will only work if you explicitly inject the value into the Derived constructor which calls the non-default Base constructor.

However, you might choose to use Property or Method injection instead. With these you don't have to add the dependency to every constructor of a derived class.

Property Injection:

class Base
{
    [Dependency]
    public IDep Dep { get; set; }
} 

Method Injection:

class Base
{
     private IDep dep;

     [InjectionMethod]
     public void Initialize(IDep dep)
     {
         this.dep = dep;
     }
}

Please note:

  • The object is instantiated (ctor injection) before method / property injection is performed
  • It might be adequate to adapt the design to not require a base class, see Composition over Inheritance
Hoxsie answered 12/9, 2014 at 5:10 Comment(0)
S
7

This is how you should solve the problem:

class abstract Base : IBase
{
    private readonly IDep dep;

    protected Base(IDep dep)
    {
        if (dep == null) throw new ArgumentNullException("dep");
        this.dep = dep;
    }
}

Now your base class has just one constructor and this constructor defines all the dependencies the class requires. There's just one way to create this class and the class will protect its invariants. The dependency is places in a private field since other classes have no use in accessing this dependency.

With this base class, the derived class will look like this:

class Derived : Base
{
    private readonly IDep dep;

    public Derived(IDep dep) : base(dep)
    {
        this.dep = dep;
    }
}

Here the derived class also has one single constructor defining the dependencies this class requires. It can't be created in a different way. In case the class uses the dependency itself, it should store the dependency in a private field for later use. Also note that because this class has just one constructor, there is no ambiguity in what constructor to call and there is no reason to mark the constructor with a [InjectionConstructor] attribute.

Do note that I agree with BatteryBackupUnit. Since I apply Dependency Injection and the SOLID principles to my applications, I see little reason for using base classes any more. The use of Composition instead of inheritance often reduces the complexity of the system.

Suppositive answered 16/9, 2014 at 14:24 Comment(2)
Yeah I can do like this. But my focus was not to use explicit Constructor call ( : base(dep)).And yes for multiple Constructor I do agree with you that i should avoid multiple Constructor. I do agree with BatteryBackupUnit that unity can not implicitly call the Injection Constructor as it is limitations of C#.netVisional
I would declare dep as protected readonly in the base class. The protected modifier allows derived classes to access dep, while readonly prevents changes to it. This makes a duplication of the dep variable and its initialization in the derived class superfluous.Unravel
I
0

Simple and straight forward solution is to have an "InjectionMethod" in your Base class.

> public abstract class Base : IBase
>     {
> 
>         private IDep dep;
> 
>         [InjectionMethod]
>         public void Initialize(IDep dep)
>         {
>             if (dep == null) throw new ArgumentNullException("dep");
>             this.dep = dep;
> 
>             OnInitialize();
>         }
> 
>         public dep DepProperty
>         {
>             get
>             {
>                 return dep;
>             }
>         }
>         protected abstract void OnInitialize();
>     }

//now your Derived class Constructor will not be forced to have the IDep Parameter

class Derived : Base
{
    public Derived()
    {

    }

    protected override void OnInitialize()
    {
        // you can access the baseclass dependency Instance in this override
        object depObject = this.DepProperty;
    }
}
Ivatts answered 16/9, 2016 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.