Pass parameters to constructor, when initializing a lazy instance
Asked Answered
R

2

4

As I know if a variable is declared Lazy, then its constructor is called when we use the Value property.

I need to pass some parameters to this Lazy instance but cannot find the correct syntax. This is not my design, I'm using MEF and ExportFactory, it returns me Lazy instances of my parts. My parts have constructors and I need to call these constructors with some parameters.

Rehearsal answered 9/12, 2010 at 9:40 Comment(0)
D
2

MEF doesn't have a built-in way for you to pass constructor parameters to a part when you create it with an ExportFactory. Something like what Wim Coenen suggests is probably the best way to achieve what you want.

Discriminate answered 9/12, 2010 at 16:31 Comment(0)
A
9

You could export your own Func instead:

public class FooFactory
{
    [Export(typeof(Func<string,int,ExportLifetimeContext<IFoo>>))]
    public ExportLifetimeContext<IFoo> CreateFoo(string param1, int param2)
    {
        Foo foo = new Foo(param1, param2);
        return new ExportLifetimeContext<IFoo>(foo,
            delegate
            {
                // Clean-up action code goes here. The client might not be able 
                // to do this through the IFoo interface because it might not
                // even expose a Dispose method.
                //
                // If you created other hidden dependencies in order to construct
                // Foo, you could also clean them up here. 
                foo.Dispose();
            });
    }
}

and import it elsewhere:

[Export(typeof(ISomething))]
public class FooUser : ISomething
{
    private readonly Func<string,int,ExportLifetimeContext<IFoo>> fooFactory;

    [ImportingConstructor]
    public FooUser(Func<string,int,ExportLifetimeContext<IFoo>> fooFactory)
    {
        this.fooFactory = fooFactory;
    }

    public void DoSomething()
    {
        using (var fooLifetime = this.fooFactory("hello", 3))
        {
            IFoo foo = fooLifetime.Value;
            ...
        }
    }
}

If you don't need the clean-up action then you could simplify this considerably by throwing out all the ExportLifetimeContext stuff.

However, some implementations of IFoo might be disposable (or depend on other disposable objects) while others are not. So the most correct thing to do is to build a "I'm done with this object" signal into the abstraction, which is what ExportLifetimeContext provides.

Anthelion answered 9/12, 2010 at 15:5 Comment(3)
Parts are not fully trusted in my case. Also since I have no idea (from exporter side) who is calling the exported Func so I need some identifier to be passed as parameter of the function. This way the part is claiming who he is. This is a security hole sine a part can claim to be somebody else and I will return sensitive data of another part to this one. This problem can be solved by design at the point I'm creating the object. At that point, using metadata, I know which part I'm creating and easily can inject it's specific dependencies to its constructor.Rehearsal
@Wim: I load plugins from a folder. Your line Foo foo = new Foo(param1, param2) gives me a problem as I do not know "Foo" at time of implementation. This works well with ExportFactory, but now I have need to pass a parameter to one type of ViewModel in the plugins. Any suggestions?Polygynist
@PatrickS: I guess you could scan the assemblies for types implementing IFoo yourself, and then invoke the constructor via reflection. It's a bit too far outside the scope of the original question to answer in full detail here, as I don't think MEF would be much help for that.Anthelion
D
2

MEF doesn't have a built-in way for you to pass constructor parameters to a part when you create it with an ExportFactory. Something like what Wim Coenen suggests is probably the best way to achieve what you want.

Discriminate answered 9/12, 2010 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.