最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C# 反射與特性:EMIT 構(gòu)建代碼

2020-07-13 10:43 作者:朝夕教育  | 我要投稿


本期我們將學(xué)習(xí) .NET Core 中,關(guān)于動態(tài)構(gòu)建代碼的知識。其中表達(dá)式樹已經(jīng)在另一個系列寫了,所以本系列主要是講述 反射,Emit ,AOP 等內(nèi)容。

如果現(xiàn)在總結(jié)一下,反射,與哪些數(shù)據(jù)結(jié)構(gòu)相關(guān)?

我們可以從 AttributeTargets 枚舉中窺見:

分別是程序集、模塊、類、結(jié)構(gòu)體、枚舉、構(gòu)造函數(shù)、方法、屬性、字段、事件、接口、參數(shù)、委托、返回值。

以往的文章中,已經(jīng)對這些進(jìn)行了很詳細(xì)的講解,我們可以中反射中獲得各種各樣的信息。當(dāng)然,我們也可以通過動態(tài)代碼,生成以上數(shù)據(jù)結(jié)構(gòu)。

動態(tài)代碼的其中一種方式是表達(dá)式樹,我們還可以使用 Emit 技術(shù)、Roslyn 技術(shù)來編寫;相關(guān)的框架有 Natasha、CS-Script 等。



01PART構(gòu)建代碼


首先我們引入一個命名空間:

using System.Reflection.Emit;

Emit 命名空間中里面有很多用于構(gòu)建動態(tài)代碼的類型,例如?AssemblyBuilder,這個類型用于構(gòu)建程序集。類推,構(gòu)建其它數(shù)據(jù)結(jié)構(gòu)例如方法屬性,則有?MethodBuilder、PropertyBuilder?。

程序集(Assembly)


AssemblyBuilder 類型定義并表示動態(tài)程序集,它是一個密封類,其定義如下:

public sealed class AssemblyBuilder : Assembly

AssemblyBuilderAccess 定義動態(tài)程序集的訪問模式,在 .NET Core 中,只有兩個枚舉:

另外,程序集的構(gòu)建方式(API)也做了變更,如果你百度看到文章AppDomain.CurrentDomain.DefineDynamicAssembly,那么你可以關(guān)閉創(chuàng)建了,說明里面的很多代碼根本無法在 .NET Core 下跑。

好了,不再贅述,我們來看看創(chuàng)建一個程序集的代碼:

AssemblyName assemblyName = new AssemblyName("MyTest"); AssemblyBuilder
assBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Run);

構(gòu)建程序集,分為兩部分:

  • AssemblyName 完整描述程序集的唯一標(biāo)識。

  • AssemblyBuilder 構(gòu)建程序集

一個完整的程序集,有很多信息的,版本、作者、構(gòu)建時間、Token 等,這些可以使用

AssemblyName 來設(shè)置。

一般一個程序集需要包含以下內(nèi)容:

  • 簡單名稱。

  • 版本號。

  • 加密密鑰對。

  • 支持的區(qū)域性。


你可以參考以下示例:

最終程序集的 AssemblyName 顯示名稱是以下格式的字符串:

Name <,culture cultureinfo=""> <,Version = Major.Minor.Build.Revi
sion> <, strongname=""> <,publickeytoken> '\0'

例如:

ExampleAssembly, Version=1.0.0.0, Culture=en, PublicKeyToken=a5d
015c7d5a0b012

另外,創(chuàng)建程序集構(gòu)建器使用?AssemblyBuilder.DefineDynamicAssembly()?而不是?new AssemblyBuilder()?。

模塊(Module)


程序集和模塊之間的區(qū)別可以參考

模塊是程序集內(nèi)代碼的邏輯集合,每個模塊可以使用不同的語言編寫,大多數(shù)情況下,一個程序集包含一個模塊。程序集包括了代碼、版本信息、元數(shù)據(jù)等。

MSDN指出:“模塊是沒有 Assembly 清單的 Microsoft 中間語言(MSIL)文件?!薄?/p>

這些就不再扯淡了。

創(chuàng)建完程序集后,我們繼續(xù)來創(chuàng)建模塊。

類型(Type)


目前步驟:

Assembly -> Module -> Type 或 Enum

ModuleBuilder 中有個?DefineType?方法用于創(chuàng)建?class?和?struct;DefineEnum方法用于創(chuàng)建?enum。

這里我們分別說明。

創(chuàng)建類或結(jié)構(gòu)體:

TypeBuilder typeBuilder = moduleBuilder.DefineType("MyTest.MyCla
ss",TypeAttributes.Public);

定義的時候,注意名稱是完整的路徑名稱,即命名空間+類型名稱。

我們可以先通過反射,獲取已經(jīng)構(gòu)建的代碼信息:

結(jié)果:

接下來將創(chuàng)建一個枚舉類型,并且生成枚舉。

我們要創(chuàng)建一個這樣的枚舉:

namespace MyTest { public enum MyEnum { Top = 1, Bottom = 2, Lef
t = 4, Right = 8, All = 16 } }

使用 Emit 的創(chuàng)建過程如下:

EnumBuilder enumBuilder = moduleBuilder.DefineEnum("MyTest.MyEn
um", TypeAttributes.Public, typeof(int));

TypeAttributes 有很多枚舉,這里只需要知道聲明這個枚舉類型為 公開的(Public);typeof(int)?是設(shè)置枚舉數(shù)值基礎(chǔ)類型。

然后 EnumBuilder 使用?DefineLiteral?方法來創(chuàng)建枚舉。

代碼如下:

我們可以使用反射將創(chuàng)建的枚舉打印出來:

Main 方法中調(diào)用:

WriteEnum(enumBuilder.CreateTypeInfo());

接下來,類型創(chuàng)建成員,就復(fù)雜得多了。

DynamicMethod定義方法與添加IL


下面我們來為 類型創(chuàng)建一個方法,并通過 Emit 向程序集中動態(tài)添加 IL。這里并不是使用 MethodBuider,而是使用 DynamicMethod。

在開始之前,請自行安裝反編譯工具 dnSpy 或者其它工具,因?yàn)檫@里涉及到 IL 代碼。

這里我們先忽略前面編寫的代碼,清空 Main 方法。

我們創(chuàng)建一個類型:

public class MyClass{}

這個類型什么都沒有。

然后使用 Emit 動態(tài)創(chuàng)建一個 方法,并且附加到 MyClass 類型中:

運(yùn)行后會打印字符串。

DynamicMethod 類型用于構(gòu)建方法,定義并表示可以編譯、執(zhí)行和丟棄的一種動態(tài)方法。 丟棄的方法可用于垃圾回收。。

ILGenerator 是 IL 代碼生成器。

EmitWriteLine 作用是打印字符串,

OpCodes.Ret 標(biāo)記 結(jié)束方法的執(zhí)行,

Invoke 將方法轉(zhuǎn)為委托執(zhí)行。

上面的示例比較簡單,請認(rèn)真記一下。

下面,我們要使用 Emit 生成一個這樣的方法:

看起來很簡單的代碼,要用 IL 來寫,就變得復(fù)雜了。

ILGenerator 正是使用 C# 代碼的形式去寫 IL,但是所有過程都必須按照 IL 的步驟去寫。

其中最重要的,便是 OpCodes 枚舉了,OpCodes 有幾十個枚舉,代表了 IL 的所有操作功能。

如果你點(diǎn)擊上面的鏈接查看 OpCodes 的枚舉,你可以看到,很多 功能碼,這么多功能碼是記不住的。我們現(xiàn)在剛開始學(xué)習(xí) Emit,這樣就會難上加難。

所以,我們要先下載能夠查看 IL 代碼的工具,方便我們探索和調(diào)整寫法。

我們看看此方法生成的 IL 代碼:

看不懂完全沒關(guān)系,因?yàn)楣P者也看不懂。

目前我們已經(jīng)獲得了上面兩大部分的信息,接下來我們使用?DynamicMethod?來動態(tài)編寫方法。

定義 Add 方法并獲取 IL 生成工具:

DynamicMethod 用于定義一個方法;ILGenerator是 IL 生成器。當(dāng)然也可以將此方法附加到一個類型中,完整代碼示例如下:

實(shí)際以上代碼與我們反編譯出來的 IL 編寫有所差異,具體俺也不知道為啥,在群里問了調(diào)試了,注釋掉那么幾行代碼,才通過的。



C# 反射與特性:EMIT 構(gòu)建代碼的評論 (共 條)

分享到微博請遵守國家法律
红安县| 上虞市| 深水埗区| 仁布县| 昔阳县| 渑池县| 同仁县| 英德市| 福安市| 伊宁市| 中西区| 江华| 崇文区| 西昌市| 宁安市| 同仁县| 夏河县| 冀州市| 舒城县| 汉寿县| 贡嘎县| 方城县| 北辰区| 兴城市| 修文县| 嫩江县| 沽源县| 高阳县| 北票市| 左云县| 罗源县| 新建县| 本溪| 武邑县| 永平县| 垣曲县| 花莲县| 游戏| 隆德县| 信阳市| 丰县|