使用Unity的Resolve for a MEF填充的Lazy List

时间:2014-08-24 09:17:40

标签: c# unity-container mef windows-phone-8.1

我真的喜欢MEF用于导出和导入用于DI我更喜欢Unity 。这是我在尝试使用Unity解决懒惰列表时遇到的问题。

我导入ViewModelBases列表:

[ImportMany]
public IEnumerable<Lazy<ViewModelBase, ViewModelMetadata>> ViewModelsLazy { get; set;}

这很好用,但是当对象初始化时,我想用Unity解析他们的构造函数参数

ViewModelsLazy.Single(v => v.Metadata.Name.Equals(viewModel)).Value

类似的东西:

unityContainer.Resolve<ViewModelsLazy.Single(v => v.Metadata.Name.Equals(viewModel)).Value>();

会很好。

我知道MEF使用[ImportingConstructor]提供了Constructor-Injection,但是如前所述,我更喜欢Unity for DI,并且通常仅使用MEF进行导出/导入。

1 个答案:

答案 0 :(得分:4)

您始终可以阅读目录以获取作为给定类型导出的类型。

此代码不会从[ImportMany]读取,而是可以分配IEnumerable而不是类上的ComposeParts。

MEF元数据也被剔除,使用这个元数据实际上需要实现接口。看起来你有一个名为ViewModelMetadata的类,它需要是一个接口。

public static class MEFExtensions
{
    public static IEnumerable<Lazy<T, M>> GetExportsResolved<T, M>(this CompositionContainer mefContainer,
                                                                   IUnityContainer unityContainer) 
        where T: class where M: class
    {
        // wrap the resolve around unity resolve then change type to T
        return mefContainer.GetExportTypesWithMetadata<T, M>()
                           .Select(kv => new Lazy<T, M>(() => unityContainer.Resolve(kv.Key) as T, kv.Value));
    }

    public static IEnumerable<KeyValuePair<Type, M>> GetExportTypesWithMetadata<T, M>(
        this CompositionContainer mefcontainer)
        where T : class where M : class
    {

        // need to examine each type to see if they have the correct export attribute and metadata
        foreach (var type in mefcontainer.GetExportTypes<T>())
        {
            // should just be one if more than one will throw exception
            // metadata or export attribute has to implement the interface
            var metadataAttribute =
                type.GetCustomAttributes()
                    .SelectMany(
                        a =>
                        a.GetType()
                         .GetCustomAttributes()
                         .OfType<MetadataAttributeAttribute>()
                         .Concat<Attribute>(new[] { a }.OfType<ExportAttribute>()))
                    .OfType<M>().SingleOrDefault();

            // if we found the correct metadata
            if (metadataAttribute != null)
            {
                // return the lazy factory
                yield return new KeyValuePair<Type, M>(type, metadataAttribute);
            }
        }
    }

    //Idea from http://www.codewrecks.com/blog/index.php/2012/05/08/getting-the-list-of-type-associated-to-a-given-export-in-mef/
    public static IEnumerable<Type> GetExportTypes<T>(this CompositionContainer mefContainer)
        where T : class
    {
        // look in the mef catalog to grab out all the types that are of type T
        return mefContainer.Catalog.Parts.Where(part => part.ExportDefinitions
                                                            .Any(
                                                                def =>
                                                                def.Metadata.ContainsKey(
                                                                    "ExportTypeIdentity") &&
                                                                def.Metadata["ExportTypeIdentity"]
                                                                    .Equals(
                                                                        typeof (T).FullName)))
                           .AsEnumerable()
                           .Select(part => ReflectionModelServices.GetPartType(part).Value);
    }
}

看起来你也试图将它用作统一容器,最好只使用一个单位容器。我们目前使用MEF来查找所有注册 - 这些注册是具有如何注册的元数据的导出属性。然后执行类似上面的操作来填充统一容器而不是属性。

你会像

一样使用它
ViewModelsLazy = mefContainer.GetExportsResolved<ViewModelBase, IViewModelMetadata>(unityContainer);

再次使用统一容器并执行类似

的操作可能会更好
var regs = mefContainer.GetExportTypesWithMetadata<ViewModelBase, IViewModelMetadata>();
foreach (var reg in regs)
{
    unityContainer.RegisterType(typeof (ViewModelBase), reg.Key, reg.Value.Name);
}

当你想要一个课程解决时,你会去团结并做一个决定,将名称作为合同名称传递。