我正在研究MEF 2.下面的代码抛出异常:
未处理的类型异常 ' System.Composition.Hosting.CompositionFailedException'发生在 System.Composition.TypedParts.dll
其他信息:缺少依赖性' MessageSenders'上 ' MEFStudy.Program'
调用SatisfyImports()方法时。为什么呢?
using System;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Hosting;
using System.Reflection;
namespace MEFStudy
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
[ImportMany]
private List<IMessageSender> MessageSenders { get; set; }
public void Run()
{
Compose();
foreach (IMessageSender sender in MessageSenders)
{
sender.Send();
}
}
private void Compose()
{
CompositionHost host = new ContainerConfiguration().WithAssembly(Assembly.GetExecutingAssembly()).CreateContainer();
host.SatisfyImports(this); // <=========== HERE
host.Dispose();
}
}
public interface IMessageSender
{
void Send();
}
[Export(typeof(IMessageSender))]
public class EmailSender1 : IMessageSender
{
public void Send()
{
Console.WriteLine("EmailSender1");
}
}
[Export(typeof(IMessageSender))]
public class EmailSender2 : IMessageSender
{
public void Send()
{
Console.WriteLine("EmailSender2");
}
}
}
根据here,有2个版本的MEF。
List<IMessageSender>
方法适用于非便携式方法。但不是便携式的。这是一个错误吗?
答案 0 :(得分:3)
我不小心更改了以下代码:
[ImportMany]
private List<IMessageSender> MessageSenders { get; set; }
到
[ImportMany]
private IEnumerable<IMessageSender> MessageSenders { get; set; }
它解决了这个问题。
但是,为什么呢?不是List<T>
IEnumerable<T>
吗?
甚至更奇怪,我将IEnumerable更改为IList,它的工作原理。为什么呢?
(我想与此分享我的解释。)
以下界面可以重现完全相同的错误。
interface IMyList<T> : IList<T>
{
}
[System.Composition.ImportMany] // MEF 2
private IMyList<IMessageSender> MessageSenders { get; set; }
以下MEF 2来源显示原因。
3 SupportedContactTypes的Equals()方法返回false,其中包含IMyList&lt;&gt;。所以在MEF2中不会返回IMyList&lt;&gt;的有效导出。 并且MEF 2不允许使用[ImportMany]属性修饰的属性的默认值。因此,在以下逻辑中,将抛出依赖性缺失异常。
所以我们可以说,ImportMany属性只支持数组和3种支持的泛型类型。
答案 1 :(得分:0)
评论时间有点太长了:
我的猜测是MEF旨在用于接口,而不是具体的类。因此,对我而言,缺少对List的依赖似乎是一种设计选择,MEF只是缺少它的导出定义。
在您期望IMyList的情况下,相同的机制适用:MEF没有与要实例化的接口关联的具体类型,因为没有为其定义导出。即使列表满足所有要求,也需要为IMyList显式导出。 (例如,这对于单元测试很方便,因为您只需要将导出更改为模拟对象。)