Могу ли я использовать MEF для создания нескольких элементов одного типа с разными аргументами конструктора? - PullRequest
2 голосов
/ 24 января 2012

У меня определен следующий интерфейс

  • IOne
  • ITwo
  • IThree
  • ICalcalculator

И иметь несколько реализаций из них

  • ClassOne: IOne
  • ClassTwo: IOne
  • ClassThree : ITwo
  • ClassFour : ITwo
  • ClassFive: IThree
  • MyCalc : ICalculator

MyCalc требует классов 1-4, однако 2 экземпляра ClassOne и ClassThree различаются как инициализация, т.е.

public MyCalc(){
    ClassOne first= new ClassOne("filePath1");
    ClassOne second = new ClassOne("filePath2");
    ClassThree third = new ClassThree ("filePath3");
    ClassThree fourth = new ClassThree ("filePath4");
}

Я пытаюсь использовать MEF для создания конструкции MyCalc. В приведенном выше примере filePathX будет в файле конфигурации. До сих пор я сделал следующее, и, похоже, это сработало, однако я чувствую, что мой нынешний метод и подход не верны. Глядя на этот подход, я связал себя с именами (ValDatePrices & EDDatePrices), и он не чище, чем мой текущий подход (см. Выше).

Есть ли более чистый способ загрузки нескольких объектов одного типа с разными аргументами ctor?

public class MyCalc: ICalculator
{
    private CompositionContainer container; 

    public MyCalc()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyCalc).Assembly));

        container = new CompositionContainer(catalog);

        try
        {

        this.container.ComposeExportedValue<ClassFive>(
               new ClassFive((ConfigurationManager.AppSettings["SomePath"])));
        this.container.ComposeExportedValue<ClassOne>(
              "ValDatePrices"
              , new ClassOne((ConfigurationManager.AppSettings["filePath1"])));
        this.container.ComposeExportedValue<ClassOne>(
              "EDDatePrices"
               , new ClassOne((ConfigurationManager.AppSettings["filePath2"])));

        this.container.ComposeParts(this);

        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }

    }

    [Import("ValDatePrices")]
    public ClassOne ValDatePrices;

    [Import("EDDatePrices")]
    public ClassOne EDDatePrices;

    [Import]
    public ClassFive SPointReader;

    public void Calculate()
    {

        Console.WriteLine(SPointReader.Result);
        Console.WriteLine(ValDatePrices.Result.Count);
        Console.WriteLine(EDDatePrices.Result.Count);

        Console.ReadKey(); 
    }
}

Использование

class Program
{
    static void Main(string[] args)
    {
        var p = new MyCalc();
        p.Calculate();
    }
}
}

Дополнительный вопрос: где должен находиться код в конструкторе MyCalc?

1 Ответ

1 голос
/ 24 января 2012

Рассматривали ли вы использование правильного контейнера DI / IoC? Это может быть легко достигнуто чистым способом, например, с помощью NInject или StructureMap .

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

MyCalculator

public class MyCalculator : ICalculator
{
    private IOne _oneFirst;
    private IOne _oneSecond;
    private ITwo _twoFirst;
    private ITwo _twoSecond;
    private IThree _three;


    public MyCalculator([Named("Val")] IOne oneFirst, [Named("ED")] IOne oneSecond,
                        [Named("Val")] ITwo twoFirst, [Named("ED")] ITwo twoSecond, IThree three)
    {
        _oneFirst = oneFirst;
        _oneSecond = oneSecond;
        _twoFirst = twoFirst;
        _twoSecond = twoSecond;
        _three = three;

    }

    public void Calculate()
    {

    }
}

Kernel

public class CalculatorModule : NinjectModule
{
    public override void Load()
    {
        Bind<IOne>().ToMethod(CreateOne).Named("Val");
        Bind<IOne>().ToMethod(CreateTwo).Named("ED");
        Bind<ITwo>().ToMethod(CreateThree).Named("Val");
        Bind<ITwo>().ToMethod(CreateFour).Named("ED");
        Bind<IThree>().To<ClassFive>();
        Bind<ICalculator>().To<MyCalculator>();

    }

    private ITwo CreateFour(IContext arg)
    {
        return new ClassFour();
    }

    private ITwo CreateThree(IContext arg)
    {
        return new ClassThree();
    }

    private IOne CreateOne(IContext context)
    {
        return new ClassOne("filePath1");
    }

    private IOne CreateTwo(IContext arg)
    {
        return new ClassTwo("filePath2");
    }


}

Примечание о ядре: Если хотите, методы могут быть сокращены до лямбда-функций, а именованные атрибуты могут быть заменены именами параметров или пользовательскими атрибутами. См. Контекстная привязка

Использование

class Program
{
    static void Main(string[] args)
    {
        StandardKernel kernel = new StandardKernel(new CalculatorModule());
        var cal = kernel.Get<ICalculator>();
        cal.Calculate();
    }
}
...