Могу ли я контролировать создание объектов с помощью MEF? - PullRequest
5 голосов
/ 22 июня 2009

Мне нужно добавить несколько точек расширения в наш существующий код, и я рассматривал MEF как возможное решение. У нас есть интерфейс IRandomNumberGenerator с реализацией по умолчанию (ConcreteRNG), которую мы хотели бы заменить. Это звучит как идеальный сценарий для MEF, но у меня возникли проблемы с тем, как мы запускаем генераторы случайных чисел. Наш текущий код выглядит так:

public class Consumer
{
    private List<IRandomNumberGenerator> generators;
    private List<double> seeds;

    public Consumer()
    {
        generators = new List<IRandomNumberGenerator>();
        seeds = new List<double>(new[] {1.0, 2.0, 3.0});

        foreach(var seed in seeds)
        {
            generators.Add(new ConcreteRNG(seed));
        }
    }
}

Другими словами, потребитель несет ответственность за создание необходимых ему ГСЧ, включая предоставление начального числа, которое требуется каждому экземпляру.

Что я хотел бы сделать, так это чтобы конкретная реализация ГСЧ была обнаружена и создана MEF (используя DirectoryCatalog). Я не уверен, как этого добиться. Я мог бы выставить свойство Generators и пометить его как [Импорт], но как мне предоставить необходимые семена?

Есть ли какой-то другой подход, который мне не хватает?

Ответы [ 3 ]

5 голосов
/ 23 июня 2009

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

public interface IRandomNumberGeneratorFactory
{
  IRandomNumberGenerator CreateGenerator(int seed);
}

[Export(typeof(IRandomNumberGeneratorFactory))]
public class ConcreateRNGFactory : IRandomNumberGeneratorFactory
{
  public IRandomNumberGenerator CreateGenerator(int seed)
  {
    return new ConcreateRNG(seed);
  }
}

public class Consumer
{
  [Import(typeof(IRandomNumberGeneratorFactory))]
  private IRandomNumberGeneratorFactory generatorFactory;
  private List<IRandomNumberGenerator> generators;    
  private List<double> seeds;    

  public Consumer()    
  {
    generators = new List<IRandomNumberGenerator>();
    seeds = new List<double>(new[] {1.0, 2.0, 3.0});

    foreach(var seed in seeds)
    {            
      generators.Add(generatorFactory.CreateGenerator(seed));
    }
  }
}
4 голосов
/ 26 декабря 2009

MEF preview 8 имеет экспериментальную поддержку для этого, хотя оно еще не включено в System.ComponentModel.Composition.dll. См. эту запись в блоге для получения дополнительной информации.

Вам нужно будет загрузить исходные коды MEF и создать решение. В папке Samples\DynamicInstantiation вы найдете сборку Microsoft.ComponentModel.Composition.DynamicInstantiation.dll. Добавьте ссылку на эту сборку и добавьте поставщика динамических реализаций в свой контейнер следующим образом:

var catalog = new DirectoryCatalog(".");
var dynamicInstantiationProvider  = new DynamicInstantiationProvider();
var container = new CompositionContainer(catalog, dynamicInstantiationProvider);
dynamicInstantiationProvider.SourceProvider = container;

Теперь ваши детали смогут импортировать PartCreator<Foo>, если им нужно динамически создавать Foo детали. Преимущество над написанием собственного фабричного класса заключается в том, что он прозрачно позаботится об импорте Foo и импорте импорта и так далее.

редактировать

  • in MEF Preview 9 PartCreator был переименован в ExportFactory, но он включен только в версию Silverlight.
  • in MEF 2 Preview 2 , ExportFactory стали включены в настольную версию. Так что ExportFactory, вероятно, станет частью следующей версии .NET Framework после .NET 4.0.
0 голосов
/ 23 июня 2009

Я полагаю, что для этого нужна функция Lazy Exports . С этой страницы:

[Import]
public Export<IMessageSender> Sender { get; set; }

В этом случае вы соглашаетесь отложить создание этого экземпляра до тех пор, пока вам действительно не понадобится экземпляр реализации. Для запроса экземпляра используйте метод [Export.GetExportedObject ()]. Обратите внимание, что этот метод никогда не будет действовать как фабрика реализаций T, поэтому его многократный вызов вернет один и тот же экземпляр объекта, возвращенный при первом вызове.

...