Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImportingConstructors & Subclasses

Tags:

c#

mef

I have an abstract base class, and a derived class. I'm trying to use MEF to inject a reference to to my WindowManager, by using [ImportingConstructor], in the base class. ie.

[ImportingConstructor]
public SomeViewModel(IWindowManager windowmanager) {...}

The issue is that before I added this, all I had was no param constructors, and the derived class is complaning about If I add a no param constructor to the base class, the WindowManager never gets injected.

Using my currently limited knowledge the only way I can think of is to change the manager import to a Property Import, and just have a no param default constructor. This kind of bugs me, as the general rule seems to prefer constructor injection for required dependencies, and property injection for optional ones.

I could add overriding [ImportingConstructor]s in my subclasses, but that seems like unnecessary duplication of code.

Is there a nicer way to do this, ie making sure my dependencies are getting injected in when the derived classes are created?

like image 733
Kage Avatar asked Apr 20 '12 07:04

Kage


1 Answers

Ignore MEF for a moment and consider this:

public abstract class BaseClass {
    protected BaseClass(IService service) { }
}

public class SubClass : BaseClass {
    public SubClass(IService service) : base(service) { }
}

Because the base class defines a single constructor, the subclass must initialise the base class, by providing an argument for the base class' constructor.

Now, with MEF, what I think you are trying to do is this:

public abstract class BaseClass {
    [ImportingConstructor]
    protected BaseClass(IService service) { }
}

[Export]
public class SubClass : BaseClass {
    public SubClass() { }
}

It sounds like you are trying to inject something into the constructor of the base class, but you can't do that, because its the resposibility of the subclass to ensure the appropriate arguments are passed to the base class of the constructor. You need to make a modification to your subclass:

[Export]
public class SubClass : BaseClass {
    [ImportingConstructor]
    public SubClass(IService service) : base(service) { }
}

Now the subclass will have the service injected and will pass it to the base class.

In terms of using Property Injection vs Constructor Injection: it is preferable to initialise a type into a usable state. That being any explicit dependencies should be required in the constructor. But, because MEF will satisfy all imports, by the time you've got your part back from the container, both constructor and property injections would have already occurred, so you could potentially use property imports instead. My preference has always been to go with constructor imports.

like image 172
Matthew Abbott Avatar answered Nov 30 '22 22:11

Matthew Abbott