WedX - журнал о программировании и компьютерных науках

Как я могу обрабатывать рекурсивную композицию в MEF?

Рассмотрим следующий пример кода, который использует MEF для создания объекта типа Importer, который импортирует объект типа ImporterExporter, который, в свою очередь, импортирует объект типа Exporter, то есть Importer -> ImporterExporter -> Exporter. Каталог управляется CompositionUtility (очевидно, упрощенный для этого примера).

Я знаю, что MEF будет рекурсивно разрешать импорт импортированных частей. Однако, поскольку я хочу иметь возможность создавать экземпляры каждого из этих классов независимо, каждый класс с импортом также составляет себя в своем конструкторе для разрешения этого импорта.

using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespace MefRecursionSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // var importerExporter = new ImporterExporter(); // include this and composition will work
            var importer = new Importer();
            Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
            Console.ReadKey();
        }
    }

    class CompositionUtility
    {
        static CompositionUtility()
        {
            var executingAssembly = Assembly.GetExecutingAssembly();
            var assemblyCatalog = new AssemblyCatalog(executingAssembly);
            _compositionContainer = new CompositionContainer(assemblyCatalog);
        }

        private static CompositionContainer _compositionContainer;
        private static bool _isComposing;

        public static void Compose(object part)
        {
            _compositionContainer.ComposeParts(part);
        }
    }

    class Importer
    {
        public Importer()
        {
            CompositionUtility.Compose(this);
        }

        [Import]
        public ImporterExporter ImporterExporter { get; set; }
    }

    [Export]
    class ImporterExporter
    {
        public ImporterExporter()
        {
            CompositionUtility.Compose(this);
        }

        [Import]
        public Exporter Exporter { get; set; }
    }

    [Export]
    class Exporter
    {
        public int Value { get { return 7; } }
    }

}

Выполнение кода как есть приводит к ошибке композиции «ComposablePart типа MefRecursionSample.Importer 'не может быть перекомпонован ....», очевидно потому, что я пытаюсь явно составить что-то, что MEF также хочет составить.

Что меня удивило, так это то, что когда я включил первую строку метода Main, т.е. создал объект типа ImporterExporter без MEF, эта «двойная композиция» больше не вызывала исключения. Это почему?

Кроме того, как я могу заставить его работать так, чтобы я мог создать каждый из них независимо, но при этом заставить их составлять себя, когда они связаны, как в образце. Я решил, что введу логический флаг _compositionInProgress на CompositionUtility и немедленно вернусь из Compose(), когда флаг будет установлен, чтобы избежать рекурсивной композиции. Есть ли способ лучше?

02.02.2012

Ответы:


1

Флаг, который я считал установкой в ​​методе CompositionUtility Compose, не работает, потому что могут быть случаи, когда строка автоматического импорта прерывается. Например, в примере вопроса, если Exporter создал экземпляр класса в своем конструкторе с помощью new, и этот класс захочет составить себя. В исходном решении вызов Ccompose этим классом возвращался бы немедленно, оставляя класс несформированным.

Поскольку я хочу, чтобы классы составляли сами себя (таким образом, чтобы их пользователи даже не знали о MEF), единственным решением было установить правило, согласно которому классы с атрибутом [Export] не должны вызывать Compose(this). Поскольку они будут автоматически составлены MEF при импорте, это приведет к «двойной композиции» и, таким образом, вызовет исключение.

Если требуется, чтобы классы, отмеченные [Export], создавались независимо через new, а не только импортировались через MEF, они должны иметь дополнительный конструктор с логическим флагом, который при правильной установке запускает композицию этого класса. Однако поведение по умолчанию должно быть без композиции, чтобы избежать вышеупомянутой «двойной композиции».

18.02.2012

2

почему бы просто не сделать это?

class Program
{
    private static CompositionContainer _compositionContainer;

    static void Main(string[] args)
    {
        //compose the container just one time in your app
        var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        _compositionContainer = new CompositionContainer(assemblyCatalog);

        var importer = _compositionContainer.GetExportedValue<Importer>();

        Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
        Console.ReadKey();
    }
}

[Export]
class Importer
{
    [ImportingConstructor]
    public Importer(ImporterExporter imex)
    {
        this.ImporterExporter = imex;
    }

    public ImporterExporter ImporterExporter { get; private set; }
}

[Export]
class ImporterExporter
{
    [ImportingConstructor]
    public ImporterExporter(Exporter exporter)
    {
        this.Exporter = exporter;
    }

    public Exporter Exporter { get; private set; }
}

[Export]
class Exporter
{
    public int Value { get { return 7; } }
}
03.02.2012
  • Я действительно хотел бы составить объект из его конструктора (если он еще не находится в композиции), поэтому пользователю класса не нужно беспокоиться о композиции MEF и можно использовать класс, как любой другой. Кроме того, это позволило бы ввести композицию в существующие классы. 06.02.2012

  • 3

    Что вы действительно хотите сделать (я думаю), так это вызвать container.SatisfyImportsOnce () для объекта, а не ComposeParts.

    ComposeParts добавляет все дерево экспорта в каталог, в то время как SatisfyImportsOnce каждый объект относится к самому себе, составляя части, и все, без регистрации рекурсивного экспорта, поэтому вы можете вызвать конструктор или использовать конструктор импорта, вы можете иметь и то, и другое.

    Джеймс.

    08.09.2013
    Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]