I have an interface:
[InheritedExport(typeof(IMetric))]
public interface IMetric { ... }
I have a Meta attribute interface:
public interface IMetricAttribute { ... }
and an attribute that implements it:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MetricAttribute : ExportAttribute, IMetricAttribute {
public string MetricName { get; set; }
public string MetricDescription { get; set; }
public MetricAttribute(string name, string description)
: base(typeof(MetricAttribute)) {
this.MetricName = name;
this.MetricDescription = description;
}
}
I then have two classes:
[Metric("MetricA","MetricA")]
public class MetricA: IMetric { ... }
[Export(typeof(IMetric))] <<<< THIS IS IMPORTANT
[Metric("MetricB", "MetricB")]
public class MetricB: IMetric { ... }
I then try to import the metrics ( i can see both in the cataloge)
The following returns be MetricA AND MetricB
var metrics = compositionContainer.GetExports<IMetric>();
However the following returns ONLY MetricB and NOT MetricA
var metrics = compositionContainer.GetExports<IMetric, IMetricAttribute>();
any idea why?
(note the duplicate export on MetricB (it already has it from implementing IMetric))
thanks
David
First time I've seen this behaviour, but from what I can understand, metadata is generated per-export at the type level. So, given:
[Metric("MetricA", "MetricA")]
public class MetricA : IMetric
{
}
You have two exports for this type. You have the export of MetricA
which is implictly provided by your MetricAttribute
, and you have the inherited export for IMetric
provided by the InheritedExport(typeof(IMetric))
attribute on your interface.
If you look at the container, you'll notice two exports defined for MetricA
. Here is the first, with its metadata:
And here is the second:
You'll notice that the metadata is done on the export of MetricA
, not the inherited export. If I added a further export, lets say [Export("test")]
to MetricA
, you get another export definition, with the same metadata items for MetricName
and MetricDescription
for the contract named "test". This shows you that as the type is analysed, the export attribute is identified, and the export definition that is created includes the metadata specified at the same level in the abstraction tree.
The easiest way to do what you want, is to drop out the InheritedExport
, and modify your definition of your MetricAttribute
to:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false), MetadataAttribute]
public class MetricAttribute : ExportAttribute, IMetricAttribute
{
public MetricAttribute(string name, string description)
: base(typeof(IMetric))
{
this.MetricName = name;
this.MetricDescription = description;
}
public string MetricName { get; private set; }
public string MetricDescription { get; private set; }
}
Where you then pass in typeof(IMetric)
to the base ExportAttribute
constructor. You then correctly get the two exports for GetExports<IMetric>()
and GetExports<IMetric, IMetricAttribute>()
.
I came across the same problem and found a differen solution which worked fine for me: I just added metadata to the interface!
[InheritedExport(typeof(IMetric))]
[Metric("name","description")]
public interface IMetric { ... }
You can leave the fields blank or use null as default, but it is important to specify the Metadata here. Then you specify your classes without export attribute:
[Metric("MetricA")]
public class MetricA: IMetric { ... }
Be aware that you can can specify just one metadata, but the second one won't be description
in this case, it will be null
! So the metadata in the interface are NOT default values.
All in all this worked for me and I can use InheritedExport with my metadata :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With