我真的喜欢用于导出和导入的 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/