元數據(Metadata)和自定義導出(Custom Export)
在MEF中,導出可提供自身的一些附加信息,我們稱之爲“元數據”。可通過元數據將導出的一些信息、屬性傳遞給導入。上一篇介紹導入的時候提到了ImportMany,在ImportMany的時候有時候可能需要根據特定的條件過濾一些匹配的導出,這時我們可以利用導出的元數據作依據。此外,由於導入部件可以使用元數據來決定要使用哪些導出,或收集有關導出的信息而不必構造導出。 因此,導入必須爲延遲導入才能使用元數據。
使用元數據需要定義一個稱爲“元數據視圖”的接口,元數據視圖中有且只能定義只讀的屬性,可以使用特性
[DefaultValue]給屬性默認值,元數據視圖中定義的所有屬性在使用時都必須賦值,否則使用改元數據的導出將與任何導入匹配失敗,當然我們也可以使用[DefaultValue]設置默認值,這樣被[DefaultValue]修飾的屬性便可以認爲是可選屬性了。例:
public interface ILogMetadata
{
[DefaultValue("FileLog")]
string LogType{ get; }
string Name{ get; }
}
使用元數據視圖的導出
[Export(typeof(ILog))]
[ExportMetadata("Name", "FileLog")]
[ExportMetadata("LogType", "FileLog")]
public class FileLog: ILog
{
}
注意:特性ExportMetadata的參數第一個爲屬性名稱,第二個是屬性的值。組合容器在組合時部件時會自動匹配所有的元數據視圖,如果有符合的元數據視圖則該導出部件視爲匹配成功。
匹配導入(匹配含有元數據修飾的導出,導入需要使用延時加載):
public class MyLog
{
[Import]
public Lazy<ILog, ILogMetadata> singleLog { get; set; }
[ImportMany]
public IEnumerable<Lazy<ILog, ILogMetadata>> logs;
}
自定義導出
在上面的示例中我們可能會想,當元數據視圖的的必選屬性有很多時,我們是不是得使用很多的[ExportMetadata]來修飾導出,另外元數據視圖的寫法也很容易出錯,其實MEF中可以對Export 和 InheritedExport 進行擴展,用於將元數據封裝到自定義特性中。
自定義特性可以指定ContractType、ContractName或任何其他元數據。 爲了定義自定義特性,必須使用 MetadataAttribute 特性來修飾繼承自 ExportAttribute(或 InheritedExportAttribute)的類。 例:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]//指定特性的作用域
public class FileLogExportAttribute : ExportAttribute
{
public FileLogExportAttribute(string logType)
: base(typeof(ILog))
{
LogType= logType;
Name = "FileLog";
}
public string LogType{ get; private set; }
public string Name{ get; private set; }
}
使用自定義導出修飾前面導出:
1 [FileLogExport("FileLog")) 2 public class FileLog: ILog 3 { 4 }
使用自定義導出的特性,ContractType是隱式定義的,