c# - 将 Unity 的 Resolve 用于 MEF 填充的惰性列表

标签 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] 提供构造函数注入(inject),但如前所述,我更喜欢使用 Unity 进行 DI,并且通常仅将 MEF 用于导出/导入。

最佳答案

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

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

此外,MEF 元数据也是类型化的,使用此元数据实际上需要实现接口(interface)。看起来您有一个名为 ViewModelMetadata 的类,它需要是一个接口(interface)。

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

当你想要一个类被解析时,你会去统一并做一个解析传递名称作为契约(Contract)名称。

关于c# - 将 Unity 的 Resolve 用于 MEF 填充的惰性列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25470215/

相关文章:

c# - 带均衡器的声音

c# - 从 Dictionary<Key, Item> 中移除元素

c# - 在单个 'IDisposable' 语句中嵌套 'using'

c# - 使用带有额外参数的 Unity Resolve 创建对象

c# - 用于二维数组的 ASP.NET MVC 5 编辑器

c# - 我可以在单层或使用的每一层中注册所有 IoC 容器组件吗?

sitecore - 在多站点环境中使用 IoC 容器

asp.net-mvc-3 - MEF 和 MVC 3 - 如何从 mef 容器动态加载嵌入 View ?

C# 单例模式和 MEF

wpf - 以 mvvm 方式从 MEF 插件获取多个相同的 View