4

I want to export type Foo with multiple metadata options:

public interface IFoo
{
    void Do ();
}

[ExportFoo ("Bar", "1.0")]
[ExportFoo ("Baz", "1.0")]
[ExportFoo ("Baz", "2.0")]
public class Foo : IFoo
{
    public void Do () {}
}

I have declared ExportFooAttribute this way:

public interface IFooMeta
{
    string Name { get; }
    string Version { get; }
}

[MetadataAttribute, AttributeUsage (AttributeTargets.Class, AllowMultiple = true)]
public class ExportFooAttribute : ExportAttribute, IFooMeta
{
    public string Name { get; private set; }
    public string Version { get; private set; }

    public ExportFooAttribute (string name, string version) : base(typeof(IFoo))
    {
        Name = name;
        Version = version;
    }
}

According to documentation, when AllowMultiple is set to true, metadata actually contains arrays of properties of the original metadata, so I import types this way:

public interface IFooMultiMeta
{
    string[] Name { get; }
    string[] Version { get; }
}

public class Program
{
    [ImportMany]
    public List<Lazy<IFoo, IFooMultiMeta>> Foos { get; set; }

    private static void Main ()
    {
        new Program().MainInternal();
    }

    private void MainInternal ()
    {
        new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly())).ComposeParts(this);
        foreach (Lazy<IFoo, IFooMultiMeta> lazyFoo in Foos)
            for (int i = 0; i < lazyFoo.Metadata.Name.Length; i++)
                Console.WriteLine("* {0} {1}", lazyFoo.Metadata.Name[i], lazyFoo.Metadata.Version[i]);
        Console.WriteLine(Equals(Foos[0].Metadata, Foos[1].Metadata));
        Console.ReadKey();
    }
}

I expected to get one instance of Foo with metadata which contains arrays of 3 values. However, I got this:

* Baz 2.0
* Baz 1.0
* Bar 1.0
* Baz 2.0
* Baz 1.0
* Bar 1.0
* Baz 2.0
* Baz 1.0
* Bar 1.0
False

What's worse, metadata instances are different, so I can't even properly filter out duplicates.

Question: How to properly export one class as satisfying multiple combinations of metadata properties?

Complete sample: http://pastebin.com/WyjN95gr

Athari
  • 33,702
  • 16
  • 105
  • 146

1 Answers1

9

The reason for the three exports is the fact that you derive your custom export metadata from the ExportAttribute. This means that for each decoration a different export is taking place. Three decorations lead to three exports.

I'm not sure why you get all {Name,Version} pairs for each export.

To overcome the three exports you can update your custom attribute to derive from Attribute instead:

[MetadataAttribute, AttributeUsage (AttributeTargets.Class, AllowMultiple = true)]
public class ExportMetaFooAttribute : Attribute, IFooMeta
{
    public string Name { get; private set; }
    public string Version { get; private set; }

    public ExportFooAttribute (string name, string version)
    {
        Name = name;
        Version = version;
    }
}

I have renamed it to ExportMetaFooAttribute since it is not an export attribute but an export metadata attribute.

Then you change your Foo class to:

[Export(typeof(IFoo))]
[ExportMetaFoo("Bar", "1.0")]
[ExportMetaFoo("Baz", "1.0")]
[ExportMetaFoo("Baz", "2.0")]
public class Foo : IFoo
{
    public void Do ()
    {}
}

As you can see now we need the extra ExportAttribute to specify that this class needs to be exported.

Panos Rontogiannis
  • 4,154
  • 1
  • 24
  • 29
  • 3
    The Name/Version pairs are coming through multiple times because the attributes are both export and metadata attributes. For each of the three exports, the values for all three attributes are also pulled in as metadata. – Matt Jul 08 '13 at 17:41