Составьте части в MEF - PullRequest
       30

Составьте части в MEF

1 голос
/ 13 сентября 2011

Рассмотрим следующую ситуацию:

[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();
  }
}

Проблема: у меня есть доступ к классу "A" и "B", но класс "C" находится в сборке, которую я не могу изменить (поэтомуне может изменить класс "C").Есть ли способ составить «А» и «Б»?

Ответы [ 3 ]

1 голос
/ 13 сентября 2011

К сожалению, без доступа к тому, что делает конструктор C, вам почти не повезло. Кажется, что конструктор C хочет инициализировать экземпляр B, используя сам тип ... обеспечивает ли он какой-либо механизм перехвата инициализации B в C?

Если бы C должен был принять экземпляр B, вы могли бы просто передать составной экземпляр B в конструктор. Если вы хотите экспортировать закрытый тип, C, вы можете сделать что-то вроде:

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();
  }
}

(Это основано на статье с разрешением Марка Симанна ).

При этом C должен выглядеть так:

public class C
{
  public C(B b)
  {

  }
}

Этот закрытый тип может быть удовлетворен автоматическим созданием 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.
1 голос
/ 13 сентября 2011

Я так не думаю, не без ссылки на экземпляр B ...

Если бы у вас была ссылка, вы могли бы позвонить:

container.SatisfyImportsOnce(instanceOfB);
0 голосов
/ 14 сентября 2011

Вы можете использовать ServiceLocator в class B вот так

class B
{
  private A a;

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