Multiple metadata with a custom data type

Feb 22, 2012 at 3:04 PM

I'm attempting to export parts along with multiple metadata defined with the same attribute. As an example consider this class:

 

    [Export(typeof(IExtension))]
    [MenuAssociation(typeof(WindowContextMenuId), CategoryName = "window context")]
    [MenuAssociation(typeof(WorkspaceContextMenuId), CategoryName = "workspace context")]
    class ContextMenuExtension : IExtension
    {

    }

 

MenuAssociation is a MetadataAttribute that contains Type and String properties. I'd like to import IExtensions in a way that allows me to view metadata in the following form:

 

    public interface IExtensionMetadata
    {
        IMenuAssociationMetadata[] Associations { get; }
    }
    public interface IMenuAssociationMetadata
    {
        Type Type { get; }
        string CategoryName { get; }
    }
 

Each IMenuAssociationMetadata instance should contain the (Type, String) info provided by a single occurence of MenuAssociationAttribute. With this setup there's a composition exception that points to c# spec 17.1.3 about "attribute parameter types". However, according to the specification, I'm passing valid parameters to the constructor of MenuAssociationAttribute (only string and Type).

I observed that I can have:

    public interface IExtensionMetadata
    {
        Type[] Type { get; }
        string[] CategoryName { get; }
    }

 

Then I get two arrays: {"window context", "workspace context"} and {WindowContextMenuId, WorkspaceContextMenuId}, which isn't too convenient.

1. Is it at least guaranteed that the order of elements in arrays will correspond to how they are defined with MenuAssociationAttribute? (That the n-th element of the string array  always corresponds to the n-th element of the type array)

2. Is there a way to get one array of (Type, string) pairs like e.g. (WindowContextMenuId, "window context") instead of two separate arrays? For my purpose I find such pairs more coherent logically .

3. Should I assume that MEF supports metadata with AllowMultiple=true, but only if the data type is one of the "attribute parameter types" mentioned in the specification?

I'm currently using MEF 2 Preview 5, if it matters.

interface IMenuAssociationMetadata
Feb 22, 2012 at 6:26 PM

Hi,

The restriction on parameter types impacts the constants you pass into the attribute, but doesn’t restrict what you can present as properties on the attribute type. So the following attribute structure might help:

public class MenuAssociationAttribute : Attribute

{

public MenuAssociationAttribute(Type type, string name)

{

// assign to _type and _name;

}

public Tuple<Type, string> Associations { get { return Tuple.Create(_type, _name); } }
}

Then the metadata view:

public interface IMenuAssociationMetadata

{

Tuple<Type, string>[] Associations { get; }

}

Let us know how you go!

Cheers,
Nick

From: rookster [email removed]
Sent: Wednesday, February 22, 2012 7:05 AM
To: Nicholas Blumhardt
Subject: Multiple metadata with a custom data type [MEF:341118]

From: rookster

I'm attempting to export parts along with multiple metadata defined with the same attribute. As an example consider this class:

    [Export(typeof(IExtension))]
    [MenuAssociation(typeof(WindowContextMenuId), CategoryName = "window context")]
    [MenuAssociation(typeof(WorkspaceContextMenuId), CategoryName = "workspace context")]
    class ContextMenuExtension : IExtension
    {
 
    }

MenuAssociation is a MetadataAttribute that contains Type and String properties. I'd like to import IExtensions in a way that allows me to view metadata in the following form:

    public interface IExtensionMetadata
    {
        IMenuAssociationMetadata[] Associations { get; }
    }
    public interface IMenuAssociationMetadata
    {
        Type Type { get; }
        string CategoryName { get; }
    }
 
 
 

Each IMenuAssociationMetadata instance should contain the (Type, String) info provided by a single occurence of MenuAssociationAttribute. With this setup there's a composition exception that points to c# spec 17.1.3 about "attribute parameter types". However, according to the specification, I'm passing valid parameters to the constructor of MenuAssociationAttribute (only string and Type).

I observed that I can have:

    public interface IExtensionMetadata
    {
        Type[] Type { get; }
        string[] CategoryName { get; }
    }

Then I get two arrays: {"window context", "workspace context"} and {WindowContextMenuId, WorkspaceContextMenuId}, which isn't too convenient.

1. Is it at least guaranteed that the order of elements in arrays will correspond to how they are defined with MenuAssociationAttribute? (That the n-th element of the string array always corresponds to the n-th element of the type array)

2. Is there a way to get one array of (Type, string) pairs like e.g. (WindowContextMenuId, "window context") instead of two separate arrays? For my purpose I find such pairs more coherent logically .

3. Should I assume that MEF supports metadata with AllowMultiple=true, but only if the data type is one of the "attribute parameter types" mentioned in the specification?

I'm currently using MEF 2 Preview 5, if it matters.

interface IMenuAssociationMetadata
Feb 22, 2012 at 7:29 PM

Hi, thank you for the answer.

I tried something very similar, but with IMenuAssociationMetadata in place of Tuple<,> (in the example IExtensionMetadata is the type that comes into Lazy<T,TMetadata> when importing). This would probably require MEF to generate a backing class not only for IExtensionMetadata, but also for inner interfaces, and their inner interfaces, so there's actually no wonder it doesn't work.

What I managed to do finally was use a class instead of interface as metadata signature:

    public class ExtensionMetadata : IExtensionMetadata
    {
        public IMenuAssociationMetadata[] Associations { get; private set; }

        public ExtensionMetadata(IDictionary<string, object> metadata)
        {
            this.Associations = //create it here from dictionary
        }
    }

IMenuAssociationMetadata instances are created 'manually' in the above constructor. Of course, I'm forced to deal with Type[] and string[], but MEF seems to provide valid number of elements in each array and in the right order. I hope it's by design!

Then I can have Lazy<IExtension, ExtensionMetadata>, which exposes only the strongly-typed metadata.

Cheers,

Paul