僅反射載入(ReflectionOnlyLoadFrom)的 .NET 程式集,如何反射獲取它的 Attribute 元數據呢?

  • 2020 年 2 月 10 日
  • 筆記

平時我們獲取一個程式集或者類型的 Attribute 是非常輕鬆的,只需要通過 GetCustomAttribute 方法就能拿到實例然後獲取其中的值。但是,有時我們僅為反射載入一些程式集的時候,獲取這些元數據就不那麼簡單了,因為我們沒有載入目標程式集中的類型。

本文介紹如何為僅反射載入的程式集讀取 Attribute 元數據資訊。


僅反射載入一個程式集

使用 ReflectionOnlyLoadFrom 可以僅以反射的方式載入一個程式集。

var extensionFilePath = @"C:UserswalterlvDesktopWalterlv.Extension.dll";  var assembly = Assembly.ReflectionOnlyLoadFrom(extensionFilePath);

獲取程式集的 Attribute(例如獲取程式集版本號)

Assembly.GetCustomAttributesData() 得到的是一個 CustomAttributeData 的列表,而這個列表中的每一項都與普通反射中拿到的特性集合不同,這裡拿到的只是特性的資訊(以下循環中的 data 變數)。

CustomAttributeData 中有 AttributeType 屬性,雖然此屬性是 Type 類型的,但是實際上它只會是 RuntimeType 類型,而不會是真實的 Attribute 的類型(因為不能保證宿主程式域中已經載入了那個類型)。

var customAttributesData = assembly.GetCustomAttributesData();  foreach (CustomAttributeData data in customAttributesData)  {      // 這裡可以針對每一個拿到的慝的資訊進行操作。  }

比如我們要獲取這個程式集的版本號,正常我們寫 assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version,但是這裡我們無法生成 AssemblyFileVersionAttribute 的實例,我們只能這麼寫:

var versionString = assembly.GetCustomAttributesData()      .FirstOrDefault(x => x.AttributeType.FullName == typeof(AssemblyFileVersionAttribute).FullName)      ?.ConstructorArguments[0].Value as string ?? "0.0";  var version = new Version(versionString);

程式碼解讀是這樣的:

  1. 我們從拿到的所有的 Attribute 元數據中找到第一個名稱與 AssemblyFileVersionAttribute 相同的數據;
  2. 從數據的構造函數參數中找到傳入的參數值,而這個值就是我們定義 AssemblyFileVersionAttribute 時傳入的參數的實際值。

因為我們知道 AssemblyFileVersionAttribute 的構造函數只有一個,所以我們確信可以從第一個參數中拿到我們想要的值。

順便一提,我們使用 AssemblyFileVersionAttribute 而不是使用 AssemblyVersionAttribute 是因為使用 .NET Core 新格式(基於 Microsoft.NET.Sdk)編譯出來的程式集默認是不帶 AssemblyVersionAttribute 的。詳見:語義版本號(Semantic Versioning) – walterlv


參考資料

本文會經常更新,請閱讀原文: https://blog.walterlv.com/post/get-attributes-for-reflection-o

本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名 呂毅 (包含鏈接: https://blog.walterlv.com ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發布。如有任何疑問,請 與我聯繫 ([email protected])