如何理解元數據
我們可以把元數據理解為隨類型一起導出的附加信息。有時候我們會考慮, 把元數據隨類型一並導出,增加一些說明,使得我們在導入的時候,可以多一些篩選條件。
默 認的類型導出帶有元數據嗎
上面的內容我說得比較簡潔,也許您不是很理解,不要緊,在編程 裡面,很多東西我們都是寫了代碼後才理解的。所以,我的理論功底比較差,最不擅長的就是長篇大論 ,還是從代碼中看吧。
我們首先要弄清楚一下問題:在我沒有手動去添加元數據的默認導出類型 ,是否帶有元數據。為了使代碼更簡單,這裡我直接把一個類導出,而不編寫公共接口了。
這裡我們直接編寫一個類,然後直接導入這個類型即可:
示例代碼定 在當前程序集中,可以在AssemblyCatalog范圍查找。
AssemblyCatalog的Parts屬性在智能提示中沒有出現(從ComposablePartCatalog類繼承下來,可能 是因為虛方法沒有被重寫,所以沒有在智能提示中顯示出來),不過的確有這個屬性,通過枚舉Parts訪 問每個導出的組件類,而在ExportDefinitions屬性中的每個ExportDefinition對象都有一個Metadata屬 性,它就是每個導出的元數據,為字典類型(IDictionary<string, object>),key是字符串類 型,value是任意對象(Object)。
運行應用程序後,我們會看到如下圖所示的內容:
這個例子表明,在默認情 況下,導出是帶有元數據的,從上面的運行結果可以猜到默認的元數據是用於說明導出組件的類型的。
如何導出元數據?
要導出元數據,除了對目標類型應用ExportAttribute特性外,還要 用ExportMetadataAttribute特性來定義元數,在定義時遵循字典結構,即構造函數的兩個參數分別代表 key和value。如下面代碼:
這兩個元數據標記本組件 的版本為200,作者是小王。我們知道元數據是IDictionary<string, object>字典結構,這就好 辦,我們在導入的時候使用Lazy<T, TMetadata>,以前我們用過Lazy<T>,現在因為帶了元 數據,所以就用Lazy<T, TMetadata>,然後讓TMetadata的類型為IDictionary<string, object>就可以了。示例代碼如下:
AssemblyCatalog cat = new AssemblyCatalog(typeof(Program).Assembly); // 組裝 CompositionContainer container = new CompositionContainer(cat); Program p = new Program(); try { container.ComposeParts(p); // 顯示元數據 if (p.f_task.Metadata.ContainsKey("Ver")) { Console.WriteLine("版本號:{0}。", p.f_task.Metadata["Ver"].ToString()); } if (p.f_task.Metadata.ContainsKey("Author")) { Console.WriteLine("作者:{0}。", p.f_task.Metadata["Author"].ToString()); } Console.Write("\n\n"); // 測試調用 p.f_task.Value.OutPut(); } catch(Exception ex) { Console.WriteLine(ex.Message); } finally { container.Dispose(); }
好了,運行一下,如圖所示,我們已經把元數據也導入了。
還有另一種較為復雜的元 數據導出導入方式,那就是自己實現的強類型元數據。我們來動手做做。
定義一個表示元數據的公共接口,名為ICustMetadata。
[MetadataViewImplementation(typeof(MyCustMetaData))] public interface ICustMetadata { int Ver { get; } //版本 string Author { get; } //作者 }
在定義接口時,並加上MetadataViewImplementation特性,且指明哪些類將實現該接口。
2、上面我們指定了實現ICustMetadata的類為MyCustMetaData,所以接下來我們要定義這個類。
public class MyCustMetaData:ICustMetadata { IDictionary<string, object> m_dic; // 構造函數 public MyCustMetaData(IDictionary<string, object> _pDic) { this.m_dic = _pDic; } public int Ver { get { if (m_dic.ContainsKey("Ver")) { return Convert.ToInt32(m_dic["Ver"]); } return -1; } } public string Author { get { if (m_dic.ContainsKey("Author")) { return m_dic["Author"].ToString(); } return string.Empty; } } }
注意:定義元數據視圖類時,必須包含帶有一個IDictionary<string, object>類型參 數的構造函數,否則將無法使用。我們通過前面的內容知道元數據其實是以字典形式存在的,故傳給元 數據視圖類的構造函數的就是元數據的原始視圖,只是我們用一個類來重封裝了一下而已。
查看本欄目
4、 把調用的代碼修改如下:
class Program { [Import] public Lazy<TestTask, ICustMetadata> f_task; static void Main(string[] args) { AssemblyCatalog cat = new AssemblyCatalog(typeof(Program).Assembly); // 組裝 CompositionContainer container = new CompositionContainer(cat); Program p = new Program(); try { container.ComposeParts(p); // 顯示元數據 Console.WriteLine("元數據視圖類型:{0}。", p.f_task.Metadata.GetType().Name); // 顯示元數據 Console.WriteLine("------- 元數據如下 --------"); Console.WriteLine("版本:{0}", p.f_task.Metadata.Ver); Console.WriteLine("作者:{0}", p.f_task.Metadata.Author); Console.Write("\n\n"); // 測試調用 p.f_task.Value.OutPut(); } catch(Exception ex) { Console.WriteLine(ex.Message); } finally { container.Dispose(); } Console.Read(); } }
最後就得到如下圖所示的結果:
元數據的實際類型正好是 我們上面定義的MyCustMetaData類。