我有我的元数据接口和属性的基础接口。
public interface IBase
{
string Name { get; }
}
public interface IAAAMetaData : IBase
{
string[] Names { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Method)]
public class AAAMetaData : ExportAttribute, IAAAMetaData
{
public AAAMetaData(string contract)
{
Name = contract;
}
public AAAMetaData(string[] contracts)
{
Names = contracts;
}
public string Name { get; set; }
public string[] Names { get; set; }
}
public interface IBBBMetaData : IBase
{
string[] Names { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Method)]
public class BBBMetaData : ExportAttribute, IBBBMetaData
{
public BBBMetaData(string contract)
{
Name = contract;
}
public BBBMetaData(string[] contracts)
{
Names = contracts;
}
public string Name { get; set; }
public string[] Names { get; set; }
}
这是我的插件:
[AAAMetaData("Test1")]
public void Plugin1(object sender, EventArgs e)
{
sender = "Plugin1";
}
[BBBMetaData("Test2")]
public void Plugin2(object sender, EventArgs e)
{
sender = "Plugin2";
}
现在当我尝试获取导出时,我得到了错误的结果。这是我用来获取导出的代码:
var exports = _container.GetExports<Action<object, EventArgs>, IAAAMetaData>();
在GetExprts<T>()
的结果中,我在列表中收到了两个项目。如果我打开列表并看到其中的项目也导入了Plugin2。这里有什么问题? IAAAMetaData
和IBMetaData
完全不同。您甚至无法将IAAAMetaData
投射到IBBBMetaData
。谁能解释一下这里发生了什么?
感谢您的帮助!
答案 0 :(得分:1)
我不知道有一个方法有多个泛型参数,但由于你没有得到编译器错误,我认为确实有一个。但是,第二个参数可能不是契约类型。 MEF中的合同由名称指定。因此,试试这个:
var exports = _container.GetExports<Action<object, EventArgs>>( "Test1" );
答案 1 :(得分:1)
这背后的原因是两个元数据接口具有完全相同的属性。每个属性的类型和名称相同。例如,如果您将接口更改为:
public interface IAAAMetaData : IBase
{
string[] AAA_Names { get; }
}
public interface IBBBMetaData : IBase
{
string[] BBB_Names { get; }
}
您将获得您期望的单一导出。
Exports and Metadata (CodePlex MEF site)的元数据过滤和DefaultValueAttribute 部分对此进行了解释:
指定元数据视图时,将进行隐式过滤 仅匹配包含定义的元数据属性的导出 在视图中。
当然,如果导出方法的签名不同,则不会发生这种情况。尝试添加额外的变量,您将获得单个导出。另一种方法是将合同名称与ExportAttribute
和ImportAttribute
一起使用。
答案 2 :(得分:0)
IMO IAAAMetaData 和 IBBBMetaData 并没有那么不同。它们实际上是相同的。
证明 - GetExports 检索两个具有相同 INNNMetaData 类型的项目,具体取决于输入 IAAAMetaData 或 IBBBMetaData < / em>的。由于具有相同的基本接口,您实际上可以写:
var exports = container.GetExports<Action<object, EventArgs>, IBase>();
你会得到两个IBase =&gt;类型的物品。 Test1和Test2。
因此,使用您的代码,我找到的唯一解决方案是使用合同名称:
var exports = container.GetExports<Action<object, EventArgs>, IAAAMetaData>().FirstOrDefault(iaaaa => iaaaa.Metadata.Name == "Test1");
在这种情况下, GetExports 的接口参数无关紧要。