C#反射与特性(一):反射基础
1. 說(shuō)明
1.1 關(guān)于反射、特性
在 《C# 7.0 本質(zhì)論》中,關(guān)于這方面的知識(shí)在 《第十八章 反射、特性和動(dòng)態(tài)編程》;在《C# 7.0 核心技術(shù)指南》中,這部分內(nèi)容在《第19章 反射和元數(shù)據(jù)》。
在這里我們可以獲得一些關(guān)聯(lián)性很大的技術(shù):反射、特性、元數(shù)據(jù);
元數(shù)據(jù):C# 編寫(xiě)的程序編譯成一個(gè)程序集,程序集會(huì)包含元數(shù)據(jù)、編譯代碼和資源。
元數(shù)據(jù)包含內(nèi)容:
程序或類(lèi)庫(kù)中每一個(gè)類(lèi)型的描述;
清單信息,包括與程序本身有關(guān)的數(shù)據(jù),以及它依賴的庫(kù);
在代碼中嵌入的自定義特性,提供與特性所修飾的構(gòu)造有關(guān)的額外信息。
反射:在運(yùn)行時(shí)檢查并使用元數(shù)據(jù)和編譯代碼的操作稱為反射。
一個(gè)程序集包含的內(nèi)容:
[圖片來(lái)自 《C# 7.0 核心技術(shù)指南》]2. 程序集操作
C# 編譯成的代碼會(huì)生成到 .dll 或 .exe 文件中,我們可以通過(guò) Assembly 類(lèi),手動(dòng)加載 程序集文件,實(shí)現(xiàn)各種操作。
Assembly 類(lèi)在?System.Reflection?命名空間中。
《C# 7.0 核心技術(shù)指南》中,列出類(lèi) Assembly 類(lèi)常用的屬性和方法:
接下來(lái)我們將通過(guò)代碼操作,了解 Assembly 的使用方法。
創(chuàng)建一個(gè)控制臺(tái)項(xiàng)目,并設(shè)置程序集描述信息。
2.1 獲取 程序集對(duì)象(Assembly)
微軟官方文檔建議使用的加載程序集的方式:
加載程序集的建議方法是使用 Load 方法,該方法標(biāo)識(shí)要由其顯示名稱(例如 "b77a5c561934e089,Version = 2.0.0.0,Culture = 中立,PublicKeyToken =")加載的程序集。該程序集的搜索遵循運(yùn)行時(shí)如何定位程序集中所述的規(guī)則。
利用 ReflectionOnlyLoad 和 ReflectionOnlyLoadFrom 方法,你可以加載用于反射的程序集,但不能加載用于執(zhí)行的程序集。例如,可通過(guò)在32位平臺(tái)上運(yùn)行的代碼來(lái)檢查面向64位平臺(tái)的程序集。
對(duì)于程序集必須按路徑標(biāo)識(shí)的罕見(jiàn)方案,會(huì)提供 LoadFile 和 LoadFrom 方法。
一般獲取程序集有三種方式:
Assembly.Load()
Assembly.LoadFrom()
Assembly.LoadFile()
以下方法可以獲取到當(dāng)前程序引用到的程序集:
AppDomain.CurrentDomain.GetAssemblies();輸出
System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798eConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nullSystem.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aSystem.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aSystem.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a2.1.1 運(yùn)行時(shí)獲取程序集
通過(guò)正在運(yùn)行的類(lèi)型、函數(shù)等形式,去獲取程序集。
Assembly 類(lèi):public static Assembly? GetAssembly(Type type);public static Assembly GetCallingAssembly();public static Assembly? GetEntryAssembly();public static Assembly GetExecutingAssembly();Type 類(lèi):{type}.Assembly解析說(shuō)明:
| Assembly | GetAssembly(Type) | 獲取在其中定義指定類(lèi)型的當(dāng)前加載的程序集 |
| Assembly | GetCallingAssembly() | 返回方法(該方法調(diào)用當(dāng)前正在執(zhí)行的方法)的 Assembly |
| Assembly | GetEntryAssembly() | 獲取默認(rèn)應(yīng)用程序域中的進(jìn)程可執(zhí)行文件。在其他的應(yīng)用程序域中,這是由 ExecuteAssembly(String)執(zhí)行的第一個(gè)可執(zhí)行文件 |
| Assembly | GetExecutingAssembly() | 獲取包含當(dāng)前執(zhí)行的代碼的程序集 |
| Type | Assembly | 返回一個(gè)類(lèi)型所在的程序集 |
2.1.2 使用方法
Assembly assem = typeof(Console).Assembly;Assembly ass = Assembly.GetExecutingAssembly();2.1.3 從文件加載程序集
| LoadFrom(String) | 已知程序集的文件名或路徑,加載程序集 |
| LoadFrom(String, Byte[], AssemblyHashAlgorithm) | 通過(guò)給定程序集文件名或路徑、哈希值及哈希算法來(lái)加載程序集 |
| LoadFrom(String, Evidence) | 在給定程序集的文件名或路徑并提供安全證據(jù)的情況下,加載程序集 |
| LoadFrom(String, Evidence, Byte[], AssemblyHashAlgorithm) | 通過(guò)給定程序集文件名或路徑、安全證據(jù)、哈希值及哈希算法來(lái)加載程序集 |
2.1.4 使用方法
Assembly ass = Assembly.LoadFrom(@"X:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.0.0\ref\netcoreapp3.0\System.Console.dll");另外還有更多中加載程序集的方法,這些方法很偏僻,沒(méi)必要列出來(lái)(因?yàn)槲也粫?huì))。
2.2 Assembly 使用
獲得 Assembly 對(duì)象后,就可以進(jìn)行一系列的騷操作。
常用的 Assembly 函數(shù)可以查看圖三。
先設(shè)置兩個(gè) Assembly 對(duì)象
Assembly assemA = typeof(Console).Assembly;Assembly assemB = Assembly.GetExecutingAssembly();2.2.1 獲取程序集完全限定名稱
Console.WriteLine("程序集完全限定名");Console.WriteLine(assemA.FullName);Console.WriteLine(assemB.FullName);程序集完全限定名 System.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null里面有個(gè) PublicKeyToken 屬性,前面我們介紹了 Assembly 獲取程序集的方式,通過(guò) PublicKeyToken ,我們也可以使用 Load 來(lái)加載程序集。
但是你可以看到上面的輸出, System.Console 有 PublicKeyToken 值,但是自己創(chuàng)建的項(xiàng)目 ConsoleApp4 沒(méi)有。
2.2.2 AssemblyName
AssmblyName 是用來(lái)完整描述程序集的類(lèi)型。
AssmblyName 是用來(lái)獲取 程序集 各種信息的類(lèi),本身不具有操作功能,僅用于獲取程序集的元數(shù)據(jù)信息。
AssmblyName 實(shí)例可以使用 Assembly 的?GetName()?方法獲取。
| CodeBase | 獲取或設(shè)置程序集的 URL 位置。 |
| ContentType | 獲取或設(shè)置指示程序集包含的內(nèi)容類(lèi)型的值。 |
| CultureInfo | 獲取或設(shè)置程序集支持的區(qū)域性。 |
| CultureName | 獲取或設(shè)置與此程序集關(guān)聯(lián)的區(qū)域性名稱。 |
| EscapedCodeBase | 獲取 URI,包括表示基本代碼的轉(zhuǎn)義符。 |
| Flags | 獲取或設(shè)置該程序集的屬性。 |
| FullName | 獲取程序集的全名(也稱為顯示名稱)。 |
| HashAlgorithm | 獲取或設(shè)置程序集清單使用的哈希算法。 |
| KeyPair | 獲取或設(shè)置用于為程序集創(chuàng)建強(qiáng)名稱簽名的加密公鑰/私鑰對(duì)。 |
| Name | 獲取或設(shè)置程序集的簡(jiǎn)單名稱。這通常(但不一定)是程序集的清單文件的文件名,不包括其擴(kuò)展名。 |
| ProcessorArchitecture | 獲取或設(shè)置一個(gè)值,該值標(biāo)識(shí)可執(zhí)行文件的目標(biāo)平臺(tái)的處理器和每字位數(shù)。 |
| Version | 獲取或設(shè)置程序集的主版本號(hào)、次版本號(hào)、內(nèi)部版本號(hào)和修訂號(hào)。 |
| VersionCompatibility | 獲取或設(shè)置與程序集同其他程序集的兼容性相關(guān)的信息。 |
輸出信息
程序集名稱: System.Console 程序集名稱: ConsoleApp4Version: 4.1 Version: 1.0Assembly CodeBase:file:///x:/Program Files/dotnet/shared/Microsoft.NETCore.App/3.0.1/System.Console.dllAssembly CodeBase:file:///X:/Users/whuanle/source/repos/ConsoleApp4/ConsoleApp4/bin/Debug/netcoreapp3.0/ConsoleApp4.dll除了?GetName(),Assembly 類(lèi)還提供了許多與成員的有關(guān)程序集的信息。例如:
GetName 方法返回一個(gè) AssemblyName 對(duì)象,該對(duì)象提供對(duì)程序集顯示名稱的各個(gè)部分的訪問(wèn)。
GetCustomAttributes 方法列出應(yīng)用于程序集的特性。
GetFiles 方法提供對(duì)程序集清單中的文件的訪問(wèn)。
GetManifestResourceNames 方法提供程序集清單中的資源的名稱。
2.3 獲取程序集的方式
上面說(shuō)到,加載程序集的方式一般使用三種方法:
Assembly.Load()
Assembly.LoadFrom()
Assembly.LoadFile()
上面已經(jīng)演示運(yùn)行時(shí)獲取和?LoadFrom?兩種獲取方式。
下面來(lái)繼續(xù)介紹?Assembly.Load()?和?Assembly.LoadFile()?。
2.3.1 Assembly.Load()
Assembly.Load()?以強(qiáng)類(lèi)型的方式去加載程序集,
強(qiáng)名稱和程序集簽名 指的是 程序集具有唯一的和不可更改的標(biāo)識(shí)。
何以為強(qiáng)類(lèi)型?通過(guò)在清單中添加如下的兩種元數(shù)據(jù)實(shí)現(xiàn):
屬于該程序集作者的唯一編號(hào);
程序集簽名后的散列值,以證實(shí)該程序集是由持有其唯一編號(hào)的作者生成;
關(guān)于這部分內(nèi)容可以參考 《C# 7.0 核心技術(shù)指南》的《18.2 強(qiáng)名稱和程序集簽名》部分,這里不再贅述。
Assembly.Load()?加載程序集,同時(shí)可以自動(dòng)加載程序集引用到的其它程序集,并且不會(huì)造成重復(fù)加載問(wèn)題。
使用示例:
Assembly assemA = Assembly.Load("System.Console");Assembly assemB = Assembly.Load("ConsoleApp4");Assembly assemC = Assembly.Load("System.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");參考:Assembly.Load 詳解(c#)
地址:https://www.cnblogs.com/weifeng123/p/8855629.html
參考:深入了解C#反射中Assembly.Load()、Assembly.LoadFrom()、Assembly.LoadF ile ()方法
地址:https://blog.csdn.net/xuchen_wang/article/details/92773260
2.3.2 Assembly.LoadFile()
Assembly.LoadFile()?跟?Assembly.LoadFrom?的使用方法一致。
區(qū)別:?Assembly.LoadFile()只會(huì)加載指定的一個(gè)程序集;?Assembly.LoadFrom?會(huì)加載一個(gè)程序集,然后自動(dòng)加載此程序集依賴的其它程序集。
總結(jié)
以上是生活随笔為你收集整理的C#反射与特性(一):反射基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: asp.net core 3.x End
- 下一篇: [译文] C# 8 已成旧闻, 向前,