【问题标题】:MEF Constructor InjectionMEF 构造函数注入
【发布时间】:2011-01-01 18:18:06
【问题描述】:

我正在尝试找出 MEF 的构造函数注入属性。我不知道如何告诉它加载构造函数的参数。

这是我要加载的属性

[ImportMany(typeof(BUsers))]
public IEnumerable<BUsers> LoadBUsers { get; set; }

这是我用来导入程序集的代码。

try
{
    var catalog = new AggregateCatalog();
    catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
    catalog.Catalogs.Add(new DirectoryCatalog("DI")); 
    var container = new CompositionContainer(catalog);
    container.ComposeParts(this);
}

这是我要加载的类

[Serializable]
[Export(typeof(BUsers))]
public class EditProfile : BUsers
{
    [ImportingConstructor]
    public EditProfile(string Method, string Version)
    {            
        Version = "2";
        Action = "Edit";
        TypeName = "EditProfile";
    }

【问题讨论】:

    标签: c# dependency-injection mef constructor-injection


    【解决方案1】:

    当您使用 ImportingConstructor 属性时,构造函数的参数变为导入。默认情况下,您要导入的内容(合同名称)基于您要导入的参数或属性的类型。所以在这种情况下,两个导入的合同类型都是字符串,第一个参数和第二个参数之间没有真正的区别。

    您似乎正在尝试使用导入来提供配置值,这不一定是它的设计目的。为了让它做你想做的事,你应该覆盖每个参数的合约名称,如下所示:

    [ImportingConstructor]
    public EditProfile([Import("Method")] string Method, [Import("Version")] string Version)
    { }
    

    然后您需要导出容器中的方法和版本。一种方法是直接添加它们:

    var container = new CompositionContainer(catalog);
    container.ComposeExportedValue("Method", "MethodValue");
    container.ComposeExportedValue("Version", "2.0");
    container.ComposeParts(this);
    

    (注意 ComposeExportedValue 实际上是在静态 AttributedModelServices 类上定义的扩展方法。)

    如果您想从某种配置文件中读取这些值,您可以创建自己的导出提供程序,该提供程序读取配置并将其中的值作为导出到容器提供。

    处理此问题的另一种方法是仅导入一个接口,该接口通过名称提供对配置值的访问,并从构造函数的主体中获取所需的值。

    【讨论】:

    • 我刚刚在 CodePlex 下载了新的。 ComposeExportedValue() 方法不在 CompositionContainer 类中。它在哪里?
    • 我想我找到了方法。它在 AttributedModelServices 类中,该方法被定义为 CompositionContainer 类的扩展方法。
    • @David.Chu.ca 是的,ComposeExportedValue 是 AttributedModelServices 类的扩展方法。
    • 好答案。但是如果我有一个需要配置的NonShared 导出怎么办。导入配置 getter 接口是有效的(如您所写),但我应该使用什么 name ?无法在对象创建和OnImportsSatisfied-call 之间拦截以设置此 name - 但在我的情况下,访问OnImportsSatisfied 中的配置是有效的。 - 我对您的回答还有一个问题:container.ComposeParts(this)this 是什么?我不认为这是当前正在创建的EditProfile 的实例。
    【解决方案2】:

    我喜欢 Daniel 的解决方案;但是,我看到的只有一件事是演员(创建 CompopositionContrainer())和导出部分之间的参数名称与自定义 CTOR 的 [ImportingConstructor] 之间的紧密耦合。例如,“方法”在两个地方都有两个匹配。如果演员和导出部分在不同的项目中,则很难维护导出部分。

    如果可能的话,我会将第二个 CTOR 添加到导出部件类中。例如:

    [Export(typeof(BUsers))] 
    public class EditProfile : BUsers
    {
        [ImportingConstructor]
        public EditProfile(EditProfileParameters ctorPars)
        : this(ctorPars.Method, ctorPars.Version) {}
    
        public EditProfile(string Method, string Version)
        {
            Version = "2";
            Action = "Edit";
            TypeName = "EditProfile";
        }
    

    EditProfileParameters 的类应该简单明了:Method 和 Version 两个属性:

    [Export]
    public class EditProfileParameters{
       public string Method { get; set; }
       public string Version { get; set; }
    }
    

    关键是在类中添加Export属性。那么MEF应该可以把这个类映射到EditProfile的CTOR的参数上。

    这是将导出部分添加到容器的示例:

    var container = new CompositionContainer(catalog);
    var instance1 = new EditProfileParameters();
    // set property values from config or other resources
    container.ComposeExportedValue(instance1);
    container.ComposeParts(this);
    

    【讨论】:

      【解决方案3】:

      虽然迟到了,但这里有另一种利用 MEF 鲜为人知的功能的方法:属性导出

      public class ObjectMother
      {
          [Export]
          public static EditProfile DefaultEditProfile
          {
              get
              {
                  var method = ConfigurationManager.AppSettings["method"];
                  var version = ConfigurationManager.AppSettings["version"];
      
                  return new EditProfile(method,version);
              }
          }
      }
      

      ObjectMother 不需要任何用法即可使其工作,并且 EditProfile 上不需要任何属性。

      【讨论】:

      • 不错的功能,但如果EditProfile 包含任何导入怎么办?在这种情况下,您需要在容器上调用 SatisfyImportsOnce。那很痛。目前我还没有真正解决这个问题的方法。
      • 在这种情况下,我们正在构建一个手动实例化您的 EditProfile 的工厂。如果 EditProfile 在构造函数中需要其他依赖项,您始终可以通过 ImportingConstructor 将这些依赖项引入工厂。我应该指出,如果您向 EditProfile 添加其他依赖项,这是您的应用程序中对该构造函数的唯一引用,您将获得编译时错误。这是一个公平的交易,恕我直言。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多