Композиция модулей, которые имеют импорт и экспорт одного(+)
От: Dimonira  
Дата: 06.06.11 09:15
Оценка:
интерфейса? Хочу сделать по одному из интерфейсов "двустороннюю связь" между двумя модулями. Модули имеют ещё ряд интерфейсов, но они "односторонние", с ними композиция создавалась без проблем. Но как только добавил реализацию и импорта и экспорта одного интерфейса в каждый модуль, так композиция вылетает с ошибкой. В сообщении об ошибке пишет, что не найдены/удовлетворены импорты/экспорты, причём не только "двустороннего" интерфейса, но и почему-то остальных (с которыми ранее композиция работала). Как разрешить трабл? Применить Lazy? Если можно, плз, подробнее.
Re: Композиция модулей, которые имеют импорт и экспорт одног
От: -VaS- Россия vaskir.blogspot.com
Дата: 06.06.11 17:48
Оценка:
Циклические зависимости не есть хорошо. Даже совсем не хорошо. Подумай над пересмотром архитектуры. Ну а если совсем никак, то Property Injection или events.
Re[2]: Композиция модулей, которые имеют импорт и экспорт од
От: Dimonira  
Дата: 06.06.11 19:53
Оценка:
Здравствуйте, -VaS-, Вы писали:

VS>Циклические зависимости не есть хорошо. Даже совсем не хорошо. Подумай над пересмотром архитектуры. Ну а если совсем никак, то Property Injection или events.


Я не понял где "циклические зависимости"?
Набросал тест (см. ниже) для проверки композиции, он, как оказалось работает. Причём я ещё добавил модуль с полным аналогом TestStr в отдельный файл (тут из примера я его удалил), с ним тоже работает — все три "модуля" соединились импортами и экспортами, каждый с тремя (с собой и с двумя другими модулями). Теперь уже не понимаю, почему моё основное приложение не работает, там сделано аналогично, просто есть ещё другие интерфейсы ("однонаправленные"), все импорты, кроме одного, объявлены ImportMany...

using System.Windows.Forms;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

namespace MEF_Test
{
    [Export(typeof(IStr))]
    public partial class FormTest : Form, IStr
    {
        public FormTest()
        {
            InitializeComponent();
            CompositionContainer container = new CompositionContainer();
            CompositionBatch batch = new CompositionBatch();
            batch.AddPart(this);
            TestStr ts = new TestStr();
            batch.AddPart(ts);
            container.Compose(batch);
            this.textBox.Text += ts.GetString();
            this.textBox.Text += this.GetString();
        }
        public string GetStr()
        {
            return "FormTest: Test string";
        }

        [ImportMany]
        public IEnumerable<IStr> recipients = null;
        public string GetString()
        {
            if (recipients != null)
            {
                string str = "";
                foreach (IStr recipient in recipients)
                    str += recipient.GetStr() + "\r\n";
                return str;
            }
            return "FormTest: No recipients!";
        }
    }

    public interface IStr
    {
        string GetStr();
    }

    [Export(typeof(IStr))]
    public class TestStr : IStr
    {
        public string GetStr()
        {
            return "TestStr: Test string";
        }

        [ImportMany]
        public IEnumerable<IStr> recipients = null;
        public string GetString()
        {
            if (recipients != null)
            {
                string str = "";
                foreach (IStr recipient in recipients)
                    str += recipient.GetStr() + "\r\n";
                return str;
            }
            return "TestStr: No recipients!";
        }
    }
}


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

FormTest: Test string
TestStr: Test string
FormTest: Test string
TestStr: Test string
Re[3]: Композиция модулей, которые имеют импорт и экспорт од
От: Dimonira  
Дата: 07.06.11 05:36
Оценка:
Нашёл ошибку: оказалось, что происходил крах в конструкторе модуля (не проинициализировал данные), поэтому композиция не срасталась (ссылка на несуществующий объект).
Как только исправил, композиция получилась.

Дальше надо понять как сделать композицию одинаковых интерфейсов не так, что все импорты со всеми экспортами, а только нужные с нужными.
Дайте плз вводную)))
mef
Re[4]: Композиция модулей, которые имеют импорт и экспорт од
От: HowardLovekraft  
Дата: 07.06.11 06:43
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>как сделать композицию одинаковых интерфейсов не так, что все импорты со всеми экспортами, а только нужные с нужными

Ниасилил.

Существуют метаданные. Фильтровать составные части можно при определении каталога, можно при запросе частей из каталога.
Надо разжевать то, что вам требуется.
Re[5]: Композиция модулей, которые имеют импорт и экспорт од
От: Dimonira  
Дата: 07.06.11 09:14
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:
HL>Ниасилил.
HL>Существуют метаданные. Фильтровать составные части можно при определении каталога, можно при запросе частей из каталога.
HL>Надо разжевать то, что вам требуется.
Попробую разъяснить. Мне надо фильтровать не части, а соединения между частями. Например, есть три модуля, у каждого из которых есть один импорт и один экспорт одного и того же контракта. Так вот мне надо соединить модули, например, в такую цепочку: экпорт.объект1.импорт -> экпорт.объект2.импорт -> экпорт.объект3.импорт.
Если ничего не предпринимать, то композиция из трёх таких модулей будет выглядеть так. Для объекта 1: объект1.импорт будет соединён с экпорт.объект1, экпорт.объект2, экпорт.объект3. Аналогично для объектов 2 и 3 — импорт каждого будет соединён со своим экспортом и экспортами двух других модулей. То есть каждый импорт объектов будет соединён со ВСЕМИ экспортами (ну и наоборот, что то же самое).
Так вот мне не надо соединять все импорты со всеми экспортами одного контракта. Мне надо каким-то образом указать кого с кем надо соединить, а кого с кем не надо.
Re[6]: Композиция модулей, которые имеют импорт и экспорт од
От: HowardLovekraft  
Дата: 07.06.11 11:22
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>Мне надо каким-то образом указать кого с кем надо соединить, а кого с кем не надо.

Т.е. все-таки нужно отфильтровать импортируемое по какому-то условию.
Здесь
Автор: HowardLovekraft
Дата: 17.03.11
я приводил решение подобной задачи.

Ваше условие как звучит?
Re[7]: Композиция модулей, которые имеют импорт и экспорт од
От: Dimonira  
Дата: 07.06.11 11:58
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

D>>Мне надо каким-то образом указать кого с кем надо соединить, а кого с кем не надо.

HL>Т.е. все-таки нужно отфильтровать импортируемое по какому-то условию.
HL>Здесь
Автор: HowardLovekraft
Дата: 17.03.11
я приводил решение подобной задачи.


HL>Ваше условие как звучит?


Вы определяете состав композиции, какие модули в неё включать. Это понятно, но мне не это нужно.
Мне нужно, чтобы в композиции были все модули какие есть (пока во всяком случае), а вот "соединения" между модулями были только определённые.
Например, если модуль имеет и импорт и экспорт одинакового контракта, зачем мне их "соединять", т.е. "замыкать" модуль сам на себя? Равно как и соединять все такие модули (если их несколько) друг с другом. Мне надо конкретно указывать (каким-то образом) кого с кем соединить.
mef
Re[8]: Композиция модулей, которые имеют импорт и экспорт од
От: HowardLovekraft  
Дата: 07.06.11 12:15
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>Вы определяете состав композиции, какие модули в неё включать

D>Мне нужно, чтобы в композиции были все модули какие есть
Не верно.
Для определения "состава композиции" нужно определить критерий для отбора составных частей.
Для решения этой задачи пишется свой наследник ComposablePartCatalog, фильтрующий каким-либо образом составные части.
В примере по ссылке никаких наследников ComposablePartCatalog нет, и контейнер использует все, что экспортируется из текущей сборки (т.е. "все модули, какие есть").

D>Мне нужно, чтобы в композиции были все модули какие есть (пока во всяком случае), а вот "соединения" между модулями были только определённые.

D>Мне надо конкретно указывать (каким-то образом) кого с кем соединить.
Что такое "соединение между модулями"? Импорт зависимостей в экземпляр экспортируемого типа?
Каким именно образом вы хотите указывать, кого с кем соединить (нужен критерий, а не реализация)? Вам все равно придется формализовать это.
Re[9]: Композиция модулей, которые имеют импорт и экспорт од
От: Dimonira  
Дата: 07.06.11 12:51
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Dimonira, Вы писали:


D>>Вы определяете состав композиции, какие модули в неё включать

D>>Мне нужно, чтобы в композиции были все модули какие есть
HL>Не верно.
HL>Для определения "состава композиции" нужно определить критерий для отбора составных частей.
HL>Для решения этой задачи пишется свой наследник ComposablePartCatalog, фильтрующий каким-либо образом составные части.
Мне не надо "определять "состава композиции"" и "критерий для отбора составных частей". Не об этом речь.
HL>В примере по ссылке никаких наследников ComposablePartCatalog нет, и контейнер использует все, что экспортируется из текущей сборки (т.е. "все модули, какие есть").
Именно так. Попробуйте запустить пример, будет видно, что когда дёргаешь один импорт (у одного модуля), дёргаются оба экспорта. Также когда дёргаешь импорт у другого. А мне надо, чтобы один импорт дёргал ОДИН конкретный экспорт.

D>>Мне нужно, чтобы в композиции были все модули какие есть (пока во всяком случае), а вот "соединения" между модулями были только определённые.

D>>Мне надо конкретно указывать (каким-то образом) кого с кем соединить.
HL>Что такое "соединение между модулями"? Импорт зависимостей в экземпляр экспортируемого типа?
HL>Каким именно образом вы хотите указывать, кого с кем соединить (нужен критерий, а не реализация)? Вам все равно придется формализовать это.
Вот об этом и вопрос как это сделать. Я именно это и спрашиваю. Пока я вынужден в рантайме в реализации всех экспортов сделать костыль: проверять от какого импорта идёт вызов (например, через метаданные — имя модуля, или ещё через тип ожидаемых данных). Вот хотелось бы как-то без костылей...
mef
Re[10]: Композиция модулей, которые имеют импорт и экспорт о
От: HowardLovekraft  
Дата: 07.06.11 12:58
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>Здравствуйте, HowardLovekraft, Вы писали:


D>что когда дёргаешь один импорт (у одного модуля), дёргаются оба экспорта

Какой пример? Что такое "дергаешь один импорт" и "дёргаются оба экспорта"?

D>Вот об этом и вопрос как это сделать. Я именно это и спрашиваю

Хм. Последняя попытка:
а) что такое "соединение между модулями"?
б) укажите критерий "соединения" (правило, условие).
Re[11]: Композиция модулей, которые имеют импорт и экспорт о
От: Dimonira  
Дата: 07.06.11 18:38
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

D>>что когда дёргаешь один импорт (у одного модуля), дёргаются оба экспорта

HL>Какой пример? Что такое "дергаешь один импорт" и "дёргаются оба экспорта"?
Вы что, издеваетесь? Пример, исходник которого я приводил в своём посте ранее.
"дергаешь один импорт" и "дёргаются оба экспорта" — это значит, что когда импортирующий модуль вызывает те экспорты, которые он получил в результате композиции.
Поскольку импорт объявлен как ImportMany, то к нему в результате композиции подключаются ВСЕ экспорты частей (в том числе и свой, если есть), имеющие одинаковый с ним контракт, а мне это не годится.

D>>Вот об этом и вопрос как это сделать. Я именно это и спрашиваю

HL>Хм. Последняя попытка:
HL>а) что такое "соединение между модулями"?
HL>б) укажите критерий "соединения" (правило, условие).
Последняя попытка:
а) Это композиция интерфейсов с одинаковыми контрактами. Что тут непонятного?
б) Критерий — конкретный модуль А с импортом контракта Х соединить (в результате композиции) ТОЛЬКО с экспортом того же контракта Х модуля Б, при том, что у модуля А также есть экспорт по тому же контракту Х, а также есть другие модули (части) с такими же импортами и экспортами того же контракта Х.
mef
Re[12]: Композиция модулей, которые имеют импорт и экспорт о
От: Dimonira  
Дата: 07.06.11 19:05
Оценка:
Кажется родилась идея. Может это и костыль, но должно работать.
Я просто буду вызывать только нужные экспорты из коллекции подключённых (а не все), которые выберу на некоем начальном этапе конфигурирования (после композиции, но до запуска в работу).
Хотя это не все ситуации решит. А именно когда есть несколько частей с импортами одинакового контракта, объявленных просто как Import, композиция, насколько я понимаю, не состоится.
Re[12]: Композиция модулей, которые имеют импорт и экспорт о
От: HowardLovekraft  
Дата: 08.06.11 08:46
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>Вы что, издеваетесь?

Ни в коей мере.
То, что очевидно вам, может быть неочевидно другому человеку. Если вы употребялете собственные термины (либо жаргонизмы), будьте готовы к тому, что они будут понятны только вам.

Традиционно: http://www.rsdn.ru/Info/Howtoask.xml

D>б) Критерий — конкретный модуль А с импортом контракта Х соединить (в результате композиции) ТОЛЬКО с экспортом того же контракта Х модуля D>Б, при том, что у модуля А также есть экспорт по тому же контракту Х, а также есть другие модули (части) с такими же импортами и экспортами D>того же контракта Х.


Легко.
Через атрибут ConnectToAttribute вы указаываете, к каким типам можно подключить данный "модуль":
    public interface IConnectToMetadata
    {
        IEnumerable<Type> ConnectTo { get; }
    }

    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class)]
    public class ConnectToAttribute : Attribute, IConnectToMetadata
    {
        public ConnectToAttribute(params Type[] connectTo)
        {
            ConnectTo = connectTo;
        }

        public IEnumerable<Type> ConnectTo { get; private set; }
    }

    public interface IContract
    {
        IEnumerable<IContract> ConnectedModules { get; }
    }

    public abstract class Module : IContract
    {
        [ImportMany]
        private IEnumerable<Lazy<IContract, IConnectToMetadata>> connectedModules;

        public IEnumerable<IContract> ConnectedModules
        {
            get
            {
                return connectedModules
                    .Where(connectedModule => connectedModule.Metadata.ConnectTo.Contains(this.GetType()))
                    .Select(connectedModule => connectedModule.Value);
            }
        }
    }

    [Export(typeof(IContract))]
    [ConnectTo(typeof(B))]
    public class A : Module
    {
    }

    [Export(typeof(IContract))]
    [ConnectTo(typeof(A))]
    public class B : Module
    {
    }

    [Export(typeof(IContract))]
    [ConnectTo(typeof(D), typeof(A))]
    public class C : Module
    {
    }

    [Export(typeof(IContract))]
    [ConnectTo(typeof(A), typeof(B), typeof(C))]
    public class D : Module
    {
    }


Использование:
    class Program
    {
        static void WriteModuleInfo(IContract module)
        {
            Console.WriteLine("Module: {0}", module);
            Console.WriteLine("\tConnected modules:");

            foreach (var connectedModule in module.ConnectedModules)
            {
                Console.WriteLine("\t\t{0}", connectedModule);
            }

            Console.WriteLine();
        }

        static void Main(string[] args)
        {
            Console.Clear();

            using (var container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly())))
            {
                foreach (var module in container.GetExportedValues<IContract>())
                {
                    WriteModuleInfo(module);
                }
            }

            Console.ReadLine();
        }
    }


Результат:
Module: ConsoleApplication1.A
        Connected modules:
                ConsoleApplication1.B
                ConsoleApplication1.C
                ConsoleApplication1.D

Module: ConsoleApplication1.B
        Connected modules:
                ConsoleApplication1.A
                ConsoleApplication1.D

Module: ConsoleApplication1.C
        Connected modules:
                ConsoleApplication1.D

Module: ConsoleApplication1.D
        Connected modules:
                ConsoleApplication1.C


Найдите 10 отличий от того, на что я давал ссылку.
Re[13]: Композиция модулей, которые имеют импорт и экспорт о
От: Dimonira  
Дата: 08.06.11 11:45
Оценка:
Ну что же, спасибо! Частично моя вчерашняя мысль оказалось у вас реализованой по уму. Но это немножко не то, хотя и такой способ тоже может быть востребован в некоторых случаях, когда конфигурация заранее жёстко известна. Если я правильно понял, то в вашем случае вы указываете критерий соединения модулей на этапе компиляции, поскольку это делается через метаданные.
А мне бы надо в рантайме, чтобы можно было бы менять композицию из готовых модулей. То есть, допустим, приложение верхнего уровня (которое делает композицию, или может сами модули) считывает откуда-то конфигурацию (например, из ini-файла), а потом в соответствии с ней осуществляет композицию. В идеале (мечта идиота) сделать визуальный конфигуратор, где можно "нарисовать" конфигурацию в виде квадратиков (имеющихся модулей), и мышкой соединять линиями импорты с экспортами (определённого цвета для каждого типа контракта). Потом сохранил конфигурацию, запустил приложение и оно работает как "нарисовано". Ну, а если конфигурацию можно менять на ходу, то это вообще был бы супер. Надо подумать как ваш способ можно было бы доработать под мои требования. Но в данный момент, к сожалению, думать некогда, меня переключили на другое неотложное дело...
Re[14]: Композиция модулей, которые имеют импорт и экспорт о
От: HowardLovekraft  
Дата: 08.06.11 14:20
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>А мне бы надо в рантайме, чтобы можно было бы менять композицию из готовых модулей

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

Можете привести пример, где такое понадобилось бы на практике?
Re[15]: Композиция модулей, которые имеют импорт и экспорт о
От: Dimonira  
Дата: 08.06.11 20:49
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Можете привести пример, где такое понадобилось бы на практике?

Спасибо за заметку, почитаю на выходных (сейчас не до того).
По поводу того, где такое может понадобиться. Ну, в принципе можно применить где угодно, было бы желание и возможности.
Я собираюсь применить в нашем софте, где делается цифровая обработка сигналов. Наш софт поставляется разным заказчикам, которые предъявляют различные требования к оборудованию: его количеству, составу и размещению (у нас основной канал передачи данных — ethernet) — это может быть от одной до нескольких рабочих станций, объединённых гигабитной сетью, по которой бегут очень приличные потоки информации (гигабит в напряге, уже нужен второй), ну и т.д. Удобство я вижу в том, что: в цифровой обработке можно менять модули для этой самой обработки (в том числе и с течением времени), отличающиеся алгоритмами и прочими внутренними фичами; в софте вообще было бы удобно составлять конфигурации из разного состава модулей под конкретные требования, типа слепил из готовых кубиков и готово, ничего компилировать в связи с этим не надо (конечно, надо ещё по уму разбить на модули по функциональности). У нас же сейчас под каждый заказ софт пишется чуть ли не с нуля, что никак нельзя считать рациональным. Модули можно считать законченными и отлаженными частями, а то у нас опять же начнут что-то менять и в результате ни черта не работает — нет работающей версии. В этом смысле MEF принуждает думать глобально и ответственно, а не только о написании своего кусочка кода, который потом никто не знает (а главное не хочет!) как и куда вставлять и использовать. Так что MEF, как мне кажется, ещё и упростит разбиение работы по программистам. Надеюсь не утомил своей философией?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.