8

I'm starting to use MEF, and I have a class with multiple constructors, like this:

[Export(typeof(ifoo))]
class foo : ifoo {
    void foo() { ... }
    [ImportingConstructor]
    void foo(object par1) { ... }
}

I am using catalog.ComposeExportedValue() when composing to supply the par1 value to second constructor:

...
catalog.ComposeExportedValue(par1Value);
catalog.ComposeParts(this);
...

To hold the components I'm using:

[ImportMany(typeof(ifoo))]
public List<Lazy<ifoo, ifoometadata>> FooList { get; set; }

And to create the foo instance I'm using the value property, FooList[0].Value.

Everthing works fine, except that the second constructor of the foo class is never called. What's wrong?

How do I select the constructor I want to use when MEF instantiates the class?

Kit
  • 20,354
  • 4
  • 60
  • 103
InterWAS
  • 183
  • 1
  • 2
  • 7
  • Have a look at http://stackoverflow.com/questions/2008133/mef-constructor-injection ... it's not *exactly* the same question, but the accepted answer sheds some light on importing constructors which may help. – Matt Hamilton May 31 '10 at 03:12
  • yes, in fact i'm using the answer from Daniel Plaisted, the problem is i cant find any examples of mef instance creation using multiple constructor definitions. – InterWAS May 31 '10 at 14:17

2 Answers2

8

MEF should use the constructor you put the ImportingConstructorAttribute on. I'm not sure what is happening for you, I wasn't able to reproduce the issue. Here is a test which shows using an ImportingConstructor on a class that also has a default constructor:

[TestClass]
public class MefTest
{
    public const string ConstructorParameterContract = "FooConstructorParameterContract";

    [TestMethod]
    public void TestConstructorInjectionWithMultipleConstructors()
    {
        string ExpectedConstructorParameterValue = "42";

        var catalog = new TypeCatalog(typeof(Foo), typeof(FooImporter));
        var container = new CompositionContainer(catalog);

        container.ComposeExportedValue<string>(ConstructorParameterContract, ExpectedConstructorParameterValue);

        var fooImporter = container.GetExportedValue<FooImporter>();

        Assert.AreEqual(1, fooImporter.FooList.Count, "Expect a single IFoo import in the list");
        Assert.AreEqual(ExpectedConstructorParameterValue, fooImporter.FooList[0].Value.ConstructorParameter, "Expected foo's ConstructorParameter to have the correct value.");
    }
}

public interface IFoo
{
    string ConstructorParameter { get; }
}

[Export(typeof(IFoo))]
public class Foo : IFoo
{
    public Foo()
    {
        ConstructorParameter = null;
    }

    [ImportingConstructor]
    public Foo([Import(MefTest.ConstructorParameterContract)]string constructorParameter)
    {
        this.ConstructorParameter = constructorParameter;
    }


    public string ConstructorParameter { get; private set; }
}

[Export]
public class FooImporter
{
    [ImportMany]
    public List<Lazy<IFoo>> FooList { get; set; }
}
Daniel Plaisted
  • 16,674
  • 4
  • 44
  • 56
  • Thanks Daniel, its working that way, but now i stuck on another problem: MEF constructor import dont work when using derivated classes, like if we have a Foo2 class that inherits from Foo in your example and alter the rest to export/import all derivated class from Foo, the constructor with parameters of base class (Foo) isnt called. Maybe its by design, to dont check the constructors of all base classes all way down. But i am using a field import in base class (Foo) and it works, so iam using this workround instead of constructor imports, at least for now. Thanks for your help Daniel. – InterWAS May 31 '10 at 20:45
  • @InterWAS It's by design. That's how constructors in .NET work- you call exactly one constructor when you create an object and it can't be a base class constructor. A derived class can call a base class's constructor in its constructor. Property/field imports probably make more sense in your case. – Daniel Plaisted Jun 01 '10 at 01:45
3

Are you passing an instance of the foo class into the ComposeExportedValue method? In that case the object has already been constructed and the constructor can't be called again, so MEF will ignore the constructor imports.

Daniel Plaisted
  • 16,674
  • 4
  • 44
  • 56
  • No, in ComposeExportedValue() i pass the values i want to inject in constructors: catalog.ComposeExportedValue(par1Value); My problem is that any suplied constructor parameters are just ignored and the class foo is instantied using only the first constructor. – InterWAS May 31 '10 at 14:09