views:

525

answers:

2

Hi, i 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 suply the par1 value to 2nd constructor:

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

To hold the components i using:

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

And to create the foo instance i using the Value property (FooList[0].Value).

Everthing works fine, except that the 2nd 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?

A: 

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
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
A: 

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
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
@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