惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
Jina AI
Jina AI
C
Check Point Blog
V
V2EX
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
A
About on SuperTechFans
D
DataBreaches.Net
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
博客园_首页
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

博客园 - 路过秋天

广电系列大流量卡选购指南:【2025-2026年度】 苹果开发者账号付款注意事项:账号实名只能用一次,DNUS注册流程又变了 苹果开发者账号付款注意事项 .NET Emit 入门教程:第七部分:实战项目1:将 DbDataReader 转实体 Taurus.MVC 微服务框架 入门开发教程:项目集成:7、微服务间的调用方式(调整):引用程序集及代码下载(新增) 一招教你戒掉抖音的瘾 .NET Emit 入门教程:第六部分:IL 指令:9:详解 ILGenerator 指令方法:运算操作指令(指令篇结束) Taurus.MVC 性能压力测试(ap 压测 和 linux 下wrk 压测):.NET 版本 .NET Core 8 部署在 IIS 的简单三步 .NET Emit 入门教程:第六部分:IL 指令:8:详解 ILGenerator 指令方法:类型转换指令 .NET Emit 入门教程:第六部分:IL 指令:7:详解 ILGenerator 指令方法:分支条件指令 Taurus.MVC 性能压力测试(ap 压测 和 linux 下wrk 压测):.NET Core 版本 CentOS 下性能测试工具 wrk 安装 .NET Emit 入门教程:第六部分:IL 指令:6:详解 ILGenerator 指令方法:方法调用指令 .NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令 .NET Emit 入门教程:第六部分:IL 指令:3:详解 ILGenerator 指令方法:参数加载指令 .NET Emit 入门教程:第六部分:IL 指令:2:详解 ILGenerator 辅助方法 .NET Emit 入门教程:第六部分:IL 指令:1:概要介绍 .NET Emit 入门教程:第五部分:动态生成方法(MethodBuilder 与 DynamicMethod)
.NET Emit 入门教程:第六部分:IL 指令:5:详解 ILGenerato...
路过秋天 · 2024-04-07 · via 博客园 - 路过秋天

前言:

上上篇介绍了 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 的使用,并在实际项目中应用动态代码生成的技术。

下一篇,我们将学习方法调用指令的相关内容。