【问题标题】:MEF GetExports<T>() is not importing correctlyMEF GetExports<T>() 未正确导入
【发布时间】:2013-07-29 17:32:29
【问题描述】:

我的元数据接口和属性有基本接口。

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&lt;T&gt;() 的结果中,我在列表中获得了两项。如果我打开列表并看到其中的项目也导入了 Plugin2。这里有什么问题? IAAAMetaDataIBMetaData 是完全不同的东西。你甚至不能将IAAAMetaData 转换为IBBBMetaData。谁能解释这里发生了什么?

感谢您的帮助!

【问题讨论】:

  • 看看这个SO entry
  • @pasty 我在您提供的链接中没有看到有用的信息。也许我不能很好地解释我的问题。如果您对理解我的问题有任何疑问,请告诉我。

标签: c# plugins mef


【解决方案1】:

这背后的原因是两个元数据接口具有完全相同的属性。每个属性的类型和名称相同。例如,如果您将界面更改为:

public interface IAAAMetaData : IBase
{
    string[] AAA_Names { get;  }
}

public interface IBBBMetaData : IBase
{
    string[] BBB_Names { get; }
}

您将获得您期望的单一导出。

Exports and Metadata (CodePlex MEF site)元数据过滤和 DefaultValueAttribute 部分对此进行了解释:

当您指定元数据视图时,将发生隐式过滤 仅匹配那些包含定义的元数据属性的导出 在视图中。

当然,如果导出方法的签名不同,则不会发生这种情况。尝试添加一个额外的变量,您将获得单个导出。另一种方法是使用带有ExportAttributeImportAttribute 的合同名称。

【讨论】:

  • 你是对的,我之前发现了问题,但是这里忘记更新了。谢谢!
【解决方案2】:

我不知道有一个具有多个泛型参数的方法,但是由于您没有收到编译器错误,我假设确实存在一个。但是,第二个参数可能不是合约类型。 MEF 中的合同由名称指定。因此,试试这个:

var exports = _container.GetExports<Action<object, EventArgs>>( "Test1" );

【讨论】:

  • 就我而言,我不能输入合同名称。我出于其他原因使用“Test1”。
【解决方案3】:

IMO IAAAAMetaDataIBBBMetaData 并没有那么不同。它们实际上是相同的。

证明 - GetExports 检索相同 INNNMetaData 类型的两个项目,具体取决于输入是 IAAAMetaData 还是 IBBBMetaData。由于相同的基本接口,您实际上可以编写:

var exports = container.GetExports<Action<object, EventArgs>, IBase>();

您将获得 IBase => Test1 和 Test2 类型的两项。

所以使用您的代码,我找到的唯一解决方案是使用合同名称:

var exports = container.GetExports<Action<object, EventArgs>, IAAAMetaData>().FirstOrDefault(iaaaa => iaaaa.Metadata.Name == "Test1"); 

在这种情况下,GetExports 的接口参数无关紧要。

【讨论】:

  • var exports = container.GetExports, IAAAMetaData>().FirstOrDefault(iaaaa => iaaaa.Metadata.Name == "Test1");它返回 [WHAT]。如果我为这两个插件添加“Test1”怎么办。我只是不想要列表中的第一项。会有很多插件使用这些属性。
  • 在调试代码时,查看 exports 并查看每个项目的类型 - 两个项目的类型相同!为了从某些特定类型中提取插件,您可能需要 FilteredCatalog 和命名属性。
猜你喜欢
  • 2012-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多