user280498
user280498

Reputation: 201

Compose parts in MEF

Consider the following situation:

[Export]
class A { }

class B 
{
  [Import]
  private A a;
}

// Instantiates class B.
class C 
{   
  public C(Type type){ /*Instantiate Class B here.*/}

  public void PerfomOperationUsingClassB() { }
}

class D
{
  void Initialize()
  {
    var catalog = new AssemblyCatalog(Assembly.GetAssembly(typeof(A)));
    var container = new CompositionContainer(catalog);

    // Is there any way to compose A with B?

    C c = new C(typeof(B));
    c.PerfomOperationUsingClassB();
  }
}

Problem: I have an access to class "A" and "B" but class "C" is located in the assembly that I can't modify (thus can't modify the class "C"). Is there any way to compose "A" and "B"?

Upvotes: 1

Views: 1629

Answers (3)

Rishabh
Rishabh

Reputation: 674

You could use the ServiceLocator in class B like this

class B
{
  private A a;

  B()
  {
    a = Microsoft.Practices.ServiceLocator.Current.GetInstance<A>();
  }
}

Upvotes: 0

Matt
Matt

Reputation: 3014

I don't think so, not without a reference to the instance of B...

If you had the reference you could call:

container.SatisfyImportsOnce(instanceOfB);

Upvotes: 1

Matthew Abbott
Matthew Abbott

Reputation: 61589

Unfortunately, without access to whatever the constructor of C is doing, you pretty much out of luck. The constructor of C seems to want to initialise an instance of B using the type itself... does it provide any mechanism of intercepting the initialisation of B within C?

If C were to accept an instance of B instead, you could easily just pass in a composed instance of B into the constructor. If you wanted to export the closed type, C, you could do something like:

public class MefAdapter<T, TExport>
{
  private readonly Func<T, TExport> _factory = CreateFactory();
  private readonly T _arg;

  [ImportingConstructor]
  public MefAdapter(T arg)
  {
    _arg = arg;
  }

  [Export]
  public TExport Export
  {
    get { return _factory(_arg); }
  }

  internal static Func<T, TExport> CreateFactory()
  {
    var tArg = typeof(T);
    var tExport = typeof(TExport);

    var arg = Expression.Parameter(tArg, "arg");
    var ctor = tExport.GetConstructor(new[] { tArg });
    var ctorExp = Expression.New(ctor, arg);

    return Expression.Lamda<Func<T, TExport>>(ctorExp, arg).Compile();
  }
}

(This is based on Mark Seemann's Resolving closed types article).

With that, should C actually look like:

public class C
{
  public C(B b)
  {

  }
}

You could have that closed type satisfied by an automatic creation of B:

var typeCatalog = new TypeCatalog(typeof(MefAdapter<C>));
var catalog = new AggregateCatalog(new DirectoryCatalog("."), typeCatalog);

var container = new CompositionContainer(catalog);

var c = container.ComposeExportedValue<C>();
// This instance of C should have a composed instance of B injected.

Upvotes: 1

Related Questions