使用导入构造函数属性

发布于 2024-08-19 22:05:04 字数 266 浏览 4 评论 0原文

我正在尝试使用 MEF 和 MVVM 构建 WPF 应用程序。我正在导出 ViewModel,但我希望 ViewModel 接受构造函数中的 Model 参数:我将创建一个特定的 Model 并将其提供给 ViewModel 的构造函数。我试图了解 ImportingConstructorAttribute 的工作原理,这似乎是拥有自定义构造函数的方法。但我不知道如何使用它。

有人可以给出一个使用 ImportingConstructorAttribute 的工作示例吗?

提前致谢

I'm trying to build a WPF application using MEF and MVVM. I'm exporting my ViewModel but I want my ViewModels to accept a Model parameter in the constructor: I will create a specific Model and supply it to ViewModel's constructor. I've tried to understand how ImportingConstructorAttribute works, it seems like it is the way to have a customized constructor. But I couldn't figure out how to use it.

Can somebody give a working example on using ImportingConstructorAttribute?

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暖风昔人 2024-08-26 22:05:04

干得好。类 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 显式向容器添加实例的替代方法是使用属性导出。然后,您可以根据需要在属性 getter 中初始化非 MEF 对象:

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

编辑以响应 comment2:首先是警告; ImportingConstructor 和 PartCreator 在 MEF 预览版 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 和基于零件元数据的动态选择。

Here you go. The class Test imports an IFoo instance via the constructor:

   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
   {
   }

edit in response to comment: I assume that by "initialized by us not a shared one" you mean that you want to manually instantiate a non-attributed, non-MEF class and inject it as a dependency for a MEF part. Typically you would do that like this:

   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
   {
   }

An alternative to adding instances explicitly to the container with ComposeExportedValue is to use a property export. You can then initialize a non-MEF object as you want in a property getter:

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

edit in response to comment2: First a warning; ImportingConstructor and PartCreator don't seem to play well together in MEF preview 8, probably because PartCreator is just a sample which is not yet well tested. Use property injection for importing PartCreator instances.

Now to answer your question; if you just want to force MEF to create multiple instances of a dependency then you just need to attribute the import a [Import("Test.foo", typeof(IFoo), RequiredCreationPolicy=CreationPolicy.NonShared)].

If you are after completely different compositions for each instance, then things are a bit more complex. You can't really have a single part (i.e. a class with MEF attributes) and have it composed differently for different part instances unless you set up multiple containers. Instead, what I do in such cases is to create multiple parts that inherit from a common class. You then have 1 subclass for each desired composition:

   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)
      {
      }
   }

This of course requires that you have a limited number of alternative compositions in mind. If the number of desired compositions cannot be enumerated at design time, you need more complex stuff, probably involving PartCreator and dynamic selection based on part metadata.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文