.NET Emit 入門教程:第六部分:IL 指令:5:詳解 ILGenerator 指令方法:創建實例指令

前言:

上上篇介紹了 IL 指令的分類以及參數加載指令,該加載指令以 Ld 開頭,將參數加載到棧中,以便於後續執行操作命令。

上一篇介紹參數存儲指令,其指令以 St 開頭,將棧中的數據,存儲到指定的變量中,以方便後續使用。

本篇將介紹創建實例指令,其指令以 New 開頭,用於在運行時動態生成並初始化對象。

創建實例指令簡介

在.NET Emit 中,使用 ILGenerator 創建實例是一項重要的操作,它允許我們動態生成對象實例和數組實例的代碼。

通過創建實例指令,我們可以在運行時動態生成並初始化對象,爲程序提供更大的靈活性和可擴展性。

創建實例指令主要包括 Newobj 指令和 Newarr 指令。

Newobj 指令用於創建新的對象實例,而 Newarr 指令則用於創建新的數組實例。

這些指令的靈活運用可以幫助我們在運行時動態地生成各種類型的實例,滿足不同場景下的需求。

在本篇文章中,我們將深入探討 ILGenerator 中的創建實例指令,詳細解析其用法和示例代碼。

通過學習本文內容,讀者將能夠掌握如何利用 ILGenerator 創建對象實例和數組實例,從而更好地理解和應用.NET Emit 技術。

1、創建實例指令:Newobj

對於該指令,其核心在於如何獲取構造函數並作爲參數傳遞,下面看一組示例。

共用代碼,定義實體(包含無參構造函數、有參構造函數、基本變量):

 public class Entity
 {
     public Entity()
     {

     }
     public Entity(int id)
     {
         this.ID = id;
     }
     public int ID;
 }

共用代碼,生成程序集,以方便後續對照參考:

AssemblyName assName = new AssemblyName("myAssembly") { Version = new Version("1.1.1.2") };
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule("myModule", "b.dll");
TypeBuilder tb = mb.DefineType("MyNameSpace.MyClass", TypeAttributes.Public | TypeAttributes.Class);

//定義靜態方法
MethodBuilder methodBuilder = tb.DefineMethod("NewObj", MethodAttributes.Public | MethodAttributes.Static, typeof(Entity), new Type[] { });
ILGenerator il = methodBuilder.GetILGenerator();

//il 代碼處......


Type classType = tb.CreateType();

ab.Save("b.dll");

A、無參數實例化:通過 Type 的 GetConstructor 實例方法獲取類型的構造函數。

ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Ret);     // 返回該值

對照生成:

B、使用參數實例化:

 ILGenerator il = methodBuilder.GetILGenerator();
 il.Emit(OpCodes.Ldc_I4, 999);
 il.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(int) }, null));
 il.Emit(OpCodes.Ret);     // 返回該值

對照生成:

小說明:

這裏構造函數的參數傳入,是通過 Ld 系列指令按順序壓入棧中。

2、創建實例指令:Newarr

該指令用於創建數組對象,該指令需要指定數組長度。

A、創建數組:

ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldc_I4, 6);
il.Emit(OpCodes.Newarr, typeof(Entity));
il.Emit(OpCodes.Ret);     // 返回該值

對照生成代碼:

小說明:

Newarr 接收的參數,是 Type 類型。

Newobj 接收的參數,是 ConstructorInfo 構造函數類型。

B、對數組賦值:引用類型

ILGenerator il = methodBuilder.GetILGenerator();

//創建數組
il.Emit(OpCodes.Ldc_I4, 3);
il.Emit(OpCodes.Newarr, typeof(Entity));

il.DeclareLocal(typeof(Entity[]));
il.DeclareLocal(typeof(Entity));
il.Emit(OpCodes.Stloc_0);//存儲數組

for (int i = 0; i < 3; i++)
{
    il.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));//定義實體類
    il.Emit(OpCodes.Stloc_1);//存儲實體類

    il.Emit(OpCodes.Ldloc_0);//加載數組
    il.Emit(OpCodes.Ldc_I4, i);//加載索引
    il.Emit(OpCodes.Ldloc_1);//加載Entity

    il.Emit(OpCodes.Stelem_Ref);//引用類型賦值
}


il.Emit(OpCodes.Ldloc_0);//加載數組
il.Emit(OpCodes.Ret);     // 返回該值

對照生成代碼:

C、對數組賦值:值類型

ILGenerator il = methodBuilder.GetILGenerator();

//創建數組
il.Emit(OpCodes.Ldc_I4, 3);
il.Emit(OpCodes.Newarr, typeof(DateTime));

il.DeclareLocal(typeof(DateTime[]));
il.DeclareLocal(typeof(DateTime));
il.Emit(OpCodes.Stloc_0);

for (int i = 0; i < 3; i++)
{// 調用 DateTime.Parse 方法創建 DateTime 實例
    MethodInfo parseMethod = typeof(DateTime).GetMethod("Parse", new Type[] { typeof(string) });
    il.Emit(OpCodes.Ldstr, DateTime.Now.ToString()); // 傳遞當前時間字符串
    il.Emit(OpCodes.Call, parseMethod);    // 調用 Parse 方法
    il.Emit(OpCodes.Stloc_1);

    il.Emit(OpCodes.Ldloc_0);//加載數組
    il.Emit(OpCodes.Ldc_I4, i);//加載索引
    il.Emit(OpCodes.Ldloc_1);//加載Entity


    il.Emit(OpCodes.Stelem, typeof(DateTime));//賦值
}

il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);     // 返回該值

對照生成代碼:

D、數組取值指令:

總結:

在.NET Emit 入門教程的第六部分中,我們深入探討了 ILGenerator 指令方法,特別是關於創建實例指令的詳細解釋。

ILGenerator 是.NET框架中的一個強大工具,用於在運行時生成和執行IL代碼。

在這篇文章中,我們學習瞭如何使用 ILGenerator 來創建實例,其中主要涉及到了兩種指令方法:newobj 和 newarr。

通過 newobj 指令,我們可以在IL代碼中調用構造函數來創建類的實例,而 newarr 指令則用於創建數組實例。

通過學習這些內容,讀者可以更深入地理解 ILGenerator 的使用,並在實際項目中應用動態代碼生成的技術。

下一篇,我們將學習方法調用指令的相關內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章