代码之家  ›  专栏  ›  技术社区  ›  Josh

是否可以参数化MEF导入?

  •  4
  • Josh  · 技术社区  · 15 年前

    我对mef比较陌生,所以我不完全了解它的功能。我在努力实现类似于unity的injectionmember的东西。

    假设我有一个导入mef部件的类。为了简单起见,让我们以下面的类作为导出部件的示例。

    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class Logger {
    
        public string Category {
            get;
            set;
        }
    
        public void Write(string text) {
        }
    
    }
    
    public class MyViewModel {
    
        [Import]
        public Logger Log {
            get;
            set;
        }
    
    }
    

    现在我想知道的是是否可以在导入时为category属性指定一个值。类似于:

    public class MyViewModel {
    
        [MyImportAttribute(Category="MyCategory")]
        public Logger Log {
            get;
            set;
        }
    
    }
    
    public class MyOtherViewModel {
    
        [MyImportAttribute(Category="MyOtherCategory")]
        public Logger Log {
            get;
            set;
        }
    
    }
    

    目前,我所做的是实现ipartimportssatisfiednotification并在代码中设置类别。但显然我宁愿把所有东西都整齐地放在一个地方。

    2 回复  |  直到 15 年前
        1
  •  6
  •   Wim Coenen    15 年前

    MEF programming guide ,请阅读 Exports and Metadata . 它显示了如何通过使用 ExportMetadata 属性或通过定义自己的自定义导出属性。

    然后可以定义 ILoggerMetadata 这样的界面:

    public interface ILoggerMetadata
    {
        string Catagory { get; }
    }
    

    做一个 ImportMany A的 IEnumerable<Lazy<ILogger,ILoggerMetadata>> 然后在下面的代码中选择所需的代码:

    private ILogger fooLogger;
    
    [ImportMany]
    public IEnumerable<Lazy<ILogger,ILoggerMetadata>> Loggers
    {
        set
        {
            this.fooLogger = value.First(x => x.Metadata.Catagory == "foo").Value;
        }
    }
    

    我同意将元数据约束直接放在import属性中会更好,但这在mef中是不可能的。(可以扩展mef来实现这一点。)

    另一种方法是导出 IFooLogger 接口来自 ILogger ,并在导入和导出中使用它。这很简单,与在导入中放置约束的效果基本相同。但是,如果您有多个元数据属性和/或许多可能的值,则此方法不起作用。

    编辑: 我很微妙地误解了您的问题;我认为这是关于限制导入,而不是用一些额外的参数配置导入的对象。

    我想 this recent post 凯萨琳·多拉德也有同样的问题。此外,在 this post about component relationships ,nicholas blumhardt建立了这样一种“参数化”关系,如 Func<X,Y> (或) Func<ILogger,string> 在你的情况下)。

    你也可以在MEF里做同样的事情 [Export(typeof(Func<ILogger,string>))] 直接在方法上的属性。或者如果你需要一个不那么模棱两可的合同,你可以定义一个 ILoggerFactory 接口和导入/导出:

    public ILoggerFactory
    {
        ILogger Create(string category);
    }
    

    最后,您仍然需要在代码中调用工厂。

        2
  •  3
  •   Josh    15 年前

    在深入研究mef之后,似乎没有办法声明性地这样做。虽然可以派生自己的导出属性,但似乎没有任何机制以任何有意义的方式派生导入属性。

    但是,与其实现ipartimportssatisfiednotification,我能做的(现在看来很明显)是在setter中设置类别。我必须放弃自动属性,但这就是生活。

    public class MyViewModel {
    
        private Logger log;
    
        [Import]
        public Logger Log {
            get { return log; }
            set {
                log = value;
                log.Category = "MyCategory";
            }
        }
    
    }
    
    推荐文章