Reputation: 3311
I have base interface for my Metadata interfaces and Attributes.
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; }
}
Here is my plugins:
[AAAMetaData("Test1")]
public void Plugin1(object sender, EventArgs e)
{
sender = "Plugin1";
}
[BBBMetaData("Test2")]
public void Plugin2(object sender, EventArgs e)
{
sender = "Plugin2";
}
Now when I try get exports I am getting wrong result. Here is the code that I am using to get exports:
var exports = _container.GetExports<Action<object, EventArgs>, IAAAMetaData>();
In the result of GetExprts<T>()
I am getting two items in the list. If I open the list and see the items inside it imported Plugin2 also. What is wrong in here? IAAAMetaData
and IBMetaData
are totally different things. You can't even cast IAAAMetaData
to IBBBMetaData
. Can anyone explain what is going on in here?
Thanks for the help!
Upvotes: 0
Views: 849
Reputation: 4172
The reason behind this is that both metadata interfaces have exactly the same properties. Same type and name for each property. If for example you change your interfaces to:
public interface IAAAMetaData : IBase
{
string[] AAA_Names { get; }
}
public interface IBBBMetaData : IBase
{
string[] BBB_Names { get; }
}
you will get the single export that you expect.
This is kind of explained in the Metadata filtering and DefaultValueAttribute section of Exports and Metadata (CodePlex MEF site):
When you specifiy a metadata view, an implicit filtering will occur to match only those exports which contain the metadata properties defined in the view.
Of course this wouldn't happen if the signature of the exported methods were different. Try adding an extra variable and you will get the single export. Also another approach would be to use contract names with ExportAttribute
and ImportAttribute
.
Upvotes: 1
Reputation: 7830
IMO IAAAMetaData and IBBBMetaData are not that different. They are actually identical.
The proof - GetExports retrieves two items of the same INNNMetaData type, depending on what the input was IAAAMetaData or IBBBMetaData. Because of the same base interface, you could actually write:
var exports = container.GetExports<Action<object, EventArgs>, IBase>();
and you will get two items of type IBase => Test1 and Test2.
So using your code, the only solution that i found was using the contract name:
var exports = container.GetExports<Action<object, EventArgs>, IAAAMetaData>().FirstOrDefault(iaaaa => iaaaa.Metadata.Name == "Test1");
In this case, the interface parameter for GetExports is irrelevant.
Upvotes: 0
Reputation: 9474
I wasn't aware that there was a method with multiple generic parameters, but since you're not getting a compiler error I assume there is indeed one. However, the second argument is probably not a contract type. Contracts in MEF are specified by name. Thus, try this:
var exports = _container.GetExports<Action<object, EventArgs>>( "Test1" );
Upvotes: 1