Использование ImportingConstructorAttribute - PullRequest
1 голос
/ 04 февраля 2010

Я пытаюсь создать приложение WPF, используя MEF и MVVM. Я экспортирую свою ViewModel, но я хочу, чтобы мои ViewModels принимали параметр Model в конструкторе: я создам конкретную модель и передам ее конструктору ViewModel. Я попытался понять, как работает ImportingConstructorAttribute, похоже, что это способ создать собственный конструктор. Но я не мог понять, как его использовать.

Может кто-нибудь привести рабочий пример использования ImportingConstructorAttribute?

Заранее спасибо

1 Ответ

5 голосов
/ 04 февраля 2010

Вот, пожалуйста. Класс Test импортирует экземпляр IFoo через конструктор:

   public class Program
   {
      public static void Main(string[] args)
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         var container = new CompositionContainer(catalog);
         Test test = container.GetExportedValue<Test>();
      }
   }

   [Export]
   public class Test
   {
      private IFoo foo;

      [ImportingConstructor]
      public Test(IFoo foo)
      {
         this.foo = foo;
      }
   }

   public interface IFoo
   {
   }

   [Export(typeof(IFoo))]
   public class Foo : IFoo
   {
   }

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

   public class Program
   {
      public static void Main(string[] args)
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         var container = new CompositionContainer(catalog);

         // create and add non-MEF instance explicitly to container
         var nonMEF = new NonMefClass();
         container.ComposeExportedValue<IFoo>("Test.foo", nonMEF);

         Test test = container.GetExportedValue<Test>();
      }
   }

   [Export]
   public class Test
   {
      private IFoo foo;

      [ImportingConstructor]
      public Test([Import("Test.foo", typeof(IFoo))] IFoo foo)
      {
         this.foo = foo;
      }
   }

   public interface IFoo
   {
   }
   public class NonMefClass : IFoo
   {
   }

Альтернативой явному добавлению экземпляров в контейнер с ComposeExportedValue является использование свойство export . Затем вы можете инициализировать объект не MEF, как вы хотите, в получателе свойства:

   public class Bar
   {
      [Export("Test.foo", typeof(IFoo))]
      public IFoo Foo
      {
         get
         {
            return new NonMefClass();
         }
      }
   }

изменить в ответ на комментарий2 : сначала предупреждение; Кажется, что ImportingConstructor и PartCreator не очень хорошо сочетаются друг с другом в MEF preview 8, возможно, потому, что PartCreator - это всего лишь пример, который еще не был хорошо протестирован. Используйте внедрение свойства для импорта экземпляров PartCreator.

Теперь, чтобы ответить на ваш вопрос; если вы просто хотите заставить MEF создать несколько экземпляров зависимости, то вам просто нужно присвоить импорту [Import("Test.foo", typeof(IFoo), RequiredCreationPolicy=CreationPolicy.NonShared)].

Если вам нужны совершенно разные композиции для каждого экземпляра, то все немного сложнее. В действительности вы не можете иметь единственную часть (то есть класс с атрибутами MEF), и она будет составлена ​​по-разному для разных экземпляров детали, если вы не настроите несколько контейнеров. Вместо этого я делаю в таких случаях несколько частей, которые наследуются от общего класса. Затем у вас есть 1 подкласс для каждой желаемой композиции:

   public class Test
   {
      private IFoo foo;

      public Test(IFoo foo)
      {
         this.foo = foo;
      }
   }

   [Export]
   public class TestComposition1 : Test
   {   
      [ImportingConstructor]
      public Test([Import("TestComposition1.foo", typeof(IFoo))] IFoo foo)
         : base(foo)
      {
      }
   }

   [Export]
   public class TestComposition2 : Test
   {   
      [ImportingConstructor]
      public Test([Import("TestComposition2.foo", typeof(IFoo))] IFoo foo)
         : base(foo)
      {
      }
   }

Это, конечно, требует, чтобы вы имели в виду ограниченное количество альтернативных композиций. Если количество желаемых композиций не может быть перечислено во время разработки, вам нужны более сложные вещи, возможно, с участием PartCreator и динамического выбора на основе метаданных детали.

...