Как внедрить N MEF-экспортов в 1 композитный сервис Unity, используя MefContrib или другой метод? - PullRequest
1 голос
/ 06 октября 2011

Допустим, у меня есть 5 отдельных сборок со следующим (предположим, имя класса отличается в каждой):

[Export(typeof(IService))]
public class Service: IService
{
    // ...
}

И у меня есть класс, который будет составным из них в моей основной сборке

public class CompositeService : IService
{
    public CompositeService(IEnumerable<IService> services)
    {
        // ...
    }
}

Я хотел бы, чтобы контейнер Unity разрешил CompositeService для IService и имел расширение MefContrib для Unity, чтобы найти 5 других экспортов и вставить их в CompositeService конструктор.

Проблема в том, что у вас не может быть N экземпляров для безымянного unityContainer.RegisterType<IService>, а также для именованных экземпляров, если все они имеют одинаковое имя.

Я думаю, что мне не хватает чего-то простого в комбинации двух технологий (Unity + MEF) с третьей (MefContrib), но, похоже, не могу понять, что это такое.

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

Ответы [ 2 ]

0 голосов
/ 21 декабря 2011

Только что попробовал то же решение от Мэтью, и оно работает нормально, Unity берет экспорт из MEF и вставляет его в конструктор (который принимает IEnumerable <>).

Не знаю, может ли это вам помочь, но могут помочь и MefContrib, и MefContrib.Integration.Unity: какое-то время я включал только последнее и сталкивался с похожими ошибками.

Обратите внимание, что все регистрации в Unity (происходящие из экспорта MEF) будут «безымянными», поэтому, если вы попробуете ResolveAll <>, вы получите пустую коллекцию, а если вы попробуете Resolve <>, вы получите получить исключение, если зарегистрировано более 1 реализации.

0 голосов
/ 10 октября 2011

Я думаю, что, вероятно, лучший подход - это перевернуть это. Вместо того, чтобы пытаться зарегистрировать свои компоненты через Unity, вы фактически оставляете обнаружение этих частей MEF. MEFContrib включает в себя механизм интеграции Unity, который позволяет вводить составные части MEF в компоненты Unity. Это было первоначально подробно описано в блоге Петра Вёдека , где он также дает вам образец. По сути, это работает так: вы можете использовать серию методов расширения на вашем UnityContainer для регистрации ваших каталогов. Внутри он создаст соответствующее расширение и подключит ваш контейнер.

Вот быстрый и грязный пример, мы создадим несколько интерфейсов:

public interface IUnityComponent
{
  IEnumerable<IMefComponent> MefComponents { get; }
}

public interface IMefComponent
{
  string Name { get; }
}

А затем некоторые образцы деталей, которые мы экспортируем (через MEF):

[Export(typeof(IMefComponent))]
public class MefComponent1 : IMefComponent
{
  public string Name { get { return "MEF Component 1"; } }
}

[Export(typeof(IMefComponent))]
public class MefComponent2 : IMefComponent
{
  public string Name { get { return "MEF Component 2"; } }
}

Теперь мы создадим еще одну часть (она будет создана с помощью Unity):

public class UnityComponent : IUnityComponent
{
  public UnityComponent(IEnumerable<IMefComponent> mefComponents) 
  { 
    // mefComponents should be provided from your MEF container.
    MefComponents = mefComponents;
  }

  public IEnumerable<IMefComponent> MefComponents { get; private set; }
}

Чтобы связать все это, нам просто нужно использовать метод расширения RegisterCatalog на вашем UnityContainer (импорт MefContrib.Integration.Unity после добавления ссылки на MEFContrib):

var container = new UnityContainer();

// Register the catalog - this handles MEF integration.
container.RegisterCatalog(new DirectoryCatalog("."));

// Register our Unity components.
container.RegisterType<IUnityComponent, UnityComponent>(new ContainerControlledLifetimeManager());

Теперь вы должны иметь возможность захватить экземпляр и перечислить части, предоставленные MEF:

// Grab an instance of our component.
var instance = container.Resolve<IUnityComponent>();
foreach (var mefComponent in instance.MefComponents)
{
  Console.WriteLine(mefComponent.Name);
}

примечание : 100% не проверено.

...