【问题标题】:How to make "defered" value export with MEF?如何使用 MEF 进行“延迟”值导出?
【发布时间】:2014-04-22 16:03:53
【问题描述】:

我有一个 Caliburn Micro 的引导程序,我使用 MEF 作为 IoC。接口实现者之一可以从它的构造函数中抛出异常。因此,当我执行以下操作时:

 CompositionBatch batch = new CompositionBatch();
 batch.AddExportedValue<IFrProvider>(new ShtrihFr());

然后我在应用程序启动时遇到异常,但我想在解决时得到它。 如何使用 MEF 实现这一目标?

更新 1。

我做了什么:

[Export(typeof (LoadingViewModel))]
public class LoadingViewModel {    
    public LoadingViewModel() {}

    [Import]
    private readonly IFrProvider frProvider;
 }

[Export(typeof(IFrProvider))]
public class ShtrihFr : IFrProvider {
    [ImportingConstructor]
    public ShtrihFr(int password = 1) {          
    }
}

所以当我执行以下操作时:

 protected override object GetInstance(Type serviceType, string key) {
        string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
        IEnumerable<object> exports = container.GetExportedValues<object>(contract);

        var exportedList = exports as IList<object> ?? exports.ToList();
        if (exportedList.Any())
            return exportedList.First();

        throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
    }

exportedList 计数为 0。它找不到实现。我检查了容器是否包含 ShtrihFr 实现的一部分。如何解决问题?

更新 2。 出于调试目的,我确实在 GetInstance 方法的开头添加了以下内容:

if (serviceType.FullName == "Microtech.Hardware.IFrProvider") {
            var export = container.GetExport<IFrProvider>();
            var frProvider = export.Value;
}

在 container.GetExport 行,我得到 ImportCardinalityMismatchException。未找到与约束匹配的导出...

【问题讨论】:

  • 问题在于采用 int 值的构造函数。它也应该为 MEF 导出。

标签: wpf inversion-of-control mef ioc-container caliburn.micro


【解决方案1】:

实现此目的的一种方法如下。在应用程序启动时创建包含应用程序所有可组合部分的Catalog,并初始化CompositionContainer。这是代码。

var catalog = new DirectoryCatalog(path to the directory that contains your dlls, "*.dll");
var compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts();

接下来用Export 属性标记你的ShtrihFr 类:

[Export(typeof(IFrProvider))]
public class ShtrihFr : IFrProvider
{
    public ShtrihFr()
    {
        throw new NotImplementedException("Not Implemented");
    }
}

这样CompositionContainerDirectoryCatalog 将只获得可组合部件及其合同的列表。不会创建实际实例,因此您不会在应用程序启动时遇到异常。

当您需要 ShtrihFr 类的实例时,可以使用以下行之一:

var part = compositionContainer.GetExportedValue<IFrProvider>();

如果构造函数抛出异常,上面一行将抛出异常,现在就是这种情况。

var part = compositionContainer.GetExport<IFrProvider>();

上述行在执行时不会抛出异常,但要获取实际实例,您需要访问part 变量的Value 属性,这将抛出异常。

更新 1:

将默认构造函数添加到ShtrihFr 类,如下所示:

[Export(typeof(IFrProvider))]
public class ShtrihFr : IFrProvider 
{
    public ShtrihFr(int password = 1) 
    {          
    }

    [ImportingConstructor]
    public ShtrihFr(int password = 1) 
    {          
    }
}

如果您需要收集导出的部分,请使用类似这样的方法,而不是使用覆盖的 GetInstance 方法:

public IEnumerable<T> GetInstances<T>(Type constraint = null)
{
    if (constraint == null)
        return compositionContainer.GetExportedValues<T>();

    return compositionContainer.GetExportedValues<T>(AttributedModelServices.GetContractName(constraint));
}

或类似的东西,如果您需要单个导出的部分:

public T GetInstance<T>(Type constraint = null)
{
    if (constraint == null)
        return compositionContainer.GetExportedValue<T>();

    return compositionContainer.GetExportedValue<T>(AttributedModelServices.GetContractName(constraint));
}

在这两种方法中,类型参数T 是您要实例化的导出部件的类型。传递给这两个方法的 constraint 参数是可选的附加约束,如果需要,将应用于类的 Export 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 2020-10-26
    相关资源
    最近更新 更多