To allow access to metadata, MEF uses a new API of. NET Framework 4, namely system. Lazy <t>. This API can be used to delay instance instantiation until the value attribute of lazy is accessed. MEF uses lazy <t, tmetadata> to further extend lazy <t> to allow access to the export metadata without instantiating the basic export.
Metadata can be used to pass the attributes of the exported object to the import part. The imported part can use this data to determine which export to use or collect export information without creating an export. Therefore, the import must be delayed before metadata can be used.
To use metadata, you usually declare an interface called "metadata View", which declares what metadata will be available. The metadata View Interface must have only attributes, and these attributes must have get accessors. When accessing metadata properties, MEF dynamically implements tmetadata and sets the value based on the metadata provided by the export.
Note:
1. If the interface/inheritance class contains fields or attributes, you must assign values to each attribute or field when exporting a specific instance, or mark the defaultvalue attribute on a required field or attribute.
2. properties in the interface can only be get and cannot be set
The following interface is an example metadata view.
Code segment
public interface IPluginMetadata{ string Name { get; } [DefaultValue(1)] int Version { get; }}
You can also use the generic set idictionary <string, Object> as the metadata view, but this will lose the advantages of the type check, so you should avoid doing so.
Generally, all attributes named in the metadata view are required, and any export that does not provide these attributes is considered a match. The defaultvalue attribute is optional. If the attribute is not included, it is assigned the default value of the parameter specified as defavalue value. The following are two different classes modified with metadata. Both classes match the previous metadata view.
Code segment
[Export(typeof(IPlugin)),ExportMetadata("Name", "Logger"),ExportMetadata("Version", 4)]public class Logger : IPlugin{} [Export(typeof(IPlugin)),ExportMetadata("Name", "Disk Writer")]//Version is not required because of the DefaultValuepublic class DWriter : IPlugin{}
Metadata is expressed after the export feature by using the exportmetadata feature. Each piece of metadata is composed of a name/value pair. The metadata name must match the name of the corresponding attribute in the metadata view, and the value is assigned to this attribute.
The import Program specifies the metadata view to be used (if any ). Imports that contain metadata are declared as delayed imports. The metadata interface is the second type parameter of lazy <t, t>. The following class imports the previous parts and metadata.
Code segment
public class Addin{ [Import] public Lazy<IPlugin, IPluginMetadata> plugin;}
In many cases, you need to combine metadata with the importmany feature to analyze available imports and select to instantiate only one import, or filter a set to match specific conditions. The following class only instantiates an iplugin object with the name value "logger.
Code segment
public class User{ [ImportMany] public IEnumerable<Lazy<IPlugin, IPluginMetadata>> plugins; public IPlugin InstantiateLogger () { IPlugin logger = null; foreach (Lazy<IPlugin, IPluginMetadata> plugin in plugins) { if (plugin.Metadata.Name = "Logger") logger = plugin.Value; } return logger; }}
The exportmetadata feature provides great flexibility. However, you must note the following when using this feature:
Metadata keys cannot be found in IDE. The part writer must know the metadata key and type valid for export.
The compiler does not verify the metadata to ensure it is correct.
Exportmetadata adds more interference information to the Code to hide the real intent.
MEF provides a solution to solve the preceding problem: Custom export.
MEF allows you to create custom export containing its own metadata. Creating a custom export includes creating a derived exportattribute that also specifies metadata.
The following class defines a custom feature.
Code segment
[MetadataAttribute][AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]public class MyAttribute : ExportAttribute{ public MyAttribute(string myMetadata) : base(typeof(IMyAddin)) { MyMetadata = myMetadata; } public string MyMetadata { get; private set; }}
This class defines a custom feature named myattribute with the protocol type imydata and some metadata named mymetadata. All attributes of the class marked with the metadataattribute attribute will be treated as metadata defined in the Custom feature. The following two statements are equivalent.
Code segment
[Export(typeof(IMyAddin),ExportMetadata("MyMetadata", "theData")]public MyAddin myAddin { get; set; } [MyAttribute("theData")]public MyAddin myAddin { get; set; }
In the first statement, the protocol type and metadata are explicitly defined. In the second declaration, the protocol type and metadata are implicitly defined in custom features. In particular, when a large amount of identical metadata (such as author or copyright information) must be applied to multiple parts, using custom features can save a lot of time and repetitive work. In addition, you can create an inheritance tree for custom features to leave room for variants.
To create optional metadata in a custom feature, you can use the defaultvalue feature. If this attribute is applied to a property in a custom property class, it specifies that the modified property is optional and does not need to be provided by the Export program. If the property value is not provided, the default value of its property type will be assigned to the Property (usuallyNull,FalseOr 0 .)
Let's look at an example:
Code segment
Public interface iclassmetadata {string classname {Get;} string otherinfo {Get;} [metadataattribute] [attributeusage (attributetargets. class, allowmultiple = false)] public class exportstudent: exportattribute, iclassmetadata {public exportstudent (): Base () {} public exportstudent (string contractname): Base (contractname) {} public exportstudent (type contracttype): Base (contracttype) {} public exportstudent (string contractname, type contracttype): Base (contractname, contracttype) {} Public String classname {Get; set ;}// [defaultvalue ("")] Public String otherinfo {Get; Set ;}} [exportstudent (classname = "Class 3, Grade 1)] public class student {public string name {Get; set;} public int age {Get; Set ;}}
Exportstudent is modified using metadataattribute, which specifies that this feature provides metadata. This feature informs MEF to view all public attributes and uses the attribute name as a key to create associated metadata for export. In this case, the unique metadata is classname and otherinfo. In this instance, the attributeusage attribute is only valid for the class and only one exportstudent attribute exists. In general, allowmultiple should be set to false; if it is true, the import program will pass a set of values instead of a single value. When multiple exports have different metadata of the same Member, allowmultiple should be kept as true.
As you can see, custom export ensures that the correct metadata is provided for a specific export. These export operations can also reduce interference information in the code, make it easier to discover, and better express the intent by specifying the domain.