news 2026/4/16 23:02:48

C#内存加载dll和EXE是不是差不多,主要是EXE有入口点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#内存加载dll和EXE是不是差不多,主要是EXE有入口点

C#内存加载dll和EXE是不是差不多,主要是EXE有入口点?

是的!在 C# 中,内存加载 DLL 和 EXE(仅限 .NET 托管程序集)的核心逻辑几乎完全一致,唯一的关键差异确实集中在「EXE 有入口点(EntryPoint)」,但本质上二者都是 CLR 可加载的托管程序集,加载和反射调用的底层规则完全相同。

下面我们从「核心共性」「关键差异」「代码示例」三个维度讲清楚,帮你彻底理解:

一、核心共性(加载 DLL/EXE 完全一致)

无论加载的是 .NET DLL 还是 EXE,只要是托管程序集,内存加载的底层逻辑、反射调用方法的规则完全相同:

  1. 加载方式一致:都通过Assembly.Load(byte[])从内存字节数组加载(而非LoadFile/LoadFrom读文件),避免磁盘依赖;
  2. 反射调用一致:加载后都通过Type.GetMethod/MethodInfo.Invoke调用方法(无论是否静态、有无参数 / 返回值);
  3. 依赖处理一致:若程序集依赖其他 DLL/EXE,都需通过AppDomain.CurrentDomain.AssemblyResolve事件处理内存加载依赖;
  4. 类型访问一致:都能访问程序集中的公开类、方法、属性(只要权限允许)。

简单说:CLR 并不区分「DLL」和「EXE」扩展名,只认「是否是符合 .NET 规范的托管程序集」—— EXE 只是「带入口点的 DLL」,DLL 是「无入口点的 EXE」。

二、关键差异(仅 2 点,核心是入口点)

维度.NET DLL.NET EXE
入口点(EntryPoint)无默认入口点(除非手动定义)必有入口点(Main方法,可通过Assembly.EntryPoint获取)
编译 / 运行特性无法直接独立运行(需宿主程序)可直接双击运行(CLR 自动调用入口点)
反射调用重点找「自定义业务方法」(如DoWork()可调用「入口点Main」或「自定义业务方法」

补充:EXE 的入口点也可以是无参 / 有参、有返回值 / 无返回值(如int Main(string[] args)),和 DLL 自定义方法的调用规则完全一致。

三、C# 代码示例(对比 DLL/EXE 内存加载)

1. 通用内存加载方法(DLL/EXE 共用)csharp
using System; using System.Reflection; using System.IO; public static class AssemblyLoader { // 核心:从字节数组加载托管程序集(DLL/EXE 通用) public static Assembly LoadFromMemory(byte[] assemblyBytes) { // 内存加载,不落地磁盘(区别于 LoadFile/LoadFrom) return Assembly.Load(assemblyBytes); } // 辅助:从文件读取字节(实际可从网络/加密存储获取) public static byte[] GetAssemblyBytes(string filePath) { return File.ReadAllBytes(filePath); } }
2. 内存加载 DLL(调用自定义方法)

假设 DLL 中有如下代码:

// 被加载的 DLL 代码 namespace MyDll { public class Calculator { // 自定义有返回值方法 public static int Add(int a, int b) { return a + b; } } }

内存加载并调用:

csharp

运行

public static void CallDllFromMemory() { try { // 1. 读取 DLL 字节(内存加载核心) byte[] dllBytes = AssemblyLoader.GetAssemblyBytes(@"C:\MyDll.dll"); Assembly assembly = AssemblyLoader.LoadFromMemory(dllBytes); // 2. 找 DLL 中的类型和方法(重点:自定义业务方法) Type calcType = assembly.GetType("MyDll.Calculator"); if (calcType == null) throw new Exception("未找到 Calculator 类型"); MethodInfo addMethod = calcType.GetMethod("Add", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(int), typeof(int) }, null); // 3. 调用方法并获取返回值 object result = addMethod.Invoke(null, new object[] { 100, 200 }); Console.WriteLine($"DLL 方法返回值:{result}"); // 输出 300 } catch (Exception ex) { Console.WriteLine("DLL 调用失败:" + ex); } }
3. 内存加载 EXE(调用入口点 + 自定义方法)假设 EXE 中有如下代码:
// 被加载的 EXE 代码 namespace MyExe { class Program { // EXE 入口点(有参数、有返回值) static int Main(string[] args) { return args?.Length ?? -1; // 返回参数个数,无参数返回 -1 } } // EXE 中的自定义公开方法(和 DLL 一样可调用) public class ExeHelper { public static string GetInfo() { return "EXE 自定义方法:" + DateTime.Now; } } }

内存加载并调用:

public static void CallExeFromMemory() { try { // 1. 读取 EXE 字节(和 DLL 加载逻辑完全一致) byte[] exeBytes = AssemblyLoader.GetAssemblyBytes(@"C:\MyExe.exe"); Assembly assembly = AssemblyLoader.LoadFromMemory(exeBytes); // ========== 场景1:调用 EXE 入口点(Main) ========== MethodInfo entryMethod = assembly.EntryPoint; // 核心:获取 EXE 入口点 if (entryMethod == null) throw new Exception("未找到 EXE 入口点"); // 调用入口点并获取返回值(和 DLL 方法调用规则一致) object entryResult = entryMethod.Invoke(null, new object[] { new string[] { "param1", "param2" } }); Console.WriteLine($"EXE 入口点返回值:{entryResult}"); // 输出 2 // ========== 场景2:调用 EXE 自定义方法(和 DLL 完全一致) ========== Type helperType = assembly.GetType("MyExe.ExeHelper"); MethodInfo infoMethod = helperType.GetMethod("GetInfo"); object infoResult = infoMethod.Invoke(null, null); Console.WriteLine(infoResult); // 输出 EXE 自定义方法:2025-xx-xx... } catch (Exception ex) { Console.WriteLine("EXE 调用失败:" + ex); } }

四、关键总结

  1. 核心结论:C# 内存加载托管 DLL/EXE 几乎无差异,唯一区别是 EXE 多了「入口点Main」,但调用入口点的逻辑和调用 DLL 自定义方法完全一致;
  2. 本质逻辑:CLR 加载的是「托管程序集」,扩展名(DLL/EXE)仅影响「是否可独立运行」,不影响内存加载和反射调用;
  3. 注意事项
    • 仅适用于 .NET 托管程序集(非托管 DLL/EXE 需用LoadLibrary/P/Invoke);
    • EXE 调用入口点时,需匹配Main的参数 / 返回值类型(如string[] argsint返回值);
    • 依赖处理:若 EXE/DLL 依赖其他程序集,需通过AssemblyResolve事件内存加载依赖项。

简单记:EXE = DLL + 入口点,内存加载和反射调用的核心逻辑完全复用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 14:21:10

17、深入探讨DevOps:概念、挑战与未来趋势

深入探讨DevOps:概念、挑战与未来趋势 1. 嘉宾介绍 Gregory Bledsoe近期加入了MThree Consulting,主要致力于帮助企业实现敏捷转型交付。此前,他在SolutionsIQ担任敏捷、精益和DevOps顾问,还撰写了大量关于DevSecOps、内核和虚拟化的文章,可在Twitter上通过@geek_king找…

作者头像 李华
网站建设 2026/4/16 14:23:17

CJ1M-CPU11-ETN可编程式控制器

CJ1M-CPU11-ETN 是欧姆龙(OMRON)CJ1M 系列的小型可编程逻辑控制器(PLC)中的 CPU 模块,广泛用于中小型自动化系统中,实现逻辑控制、数据处理及网络通讯。以下是详细信息整理:CJ1M-CPU11-ETN 主要…

作者头像 李华
网站建设 2026/4/15 22:00:40

国内做TikTok怎么变现?主流变现模式全解析

TikTok已经成为全球最大的短视频平台之一,拥有超过15亿月活用户,对于国内出海个人、团队和商家来说是一个极具潜力的变现渠道。今天我们整合主流变现方式,按照路径分类细化每种模式应具备的必要条件、操作技巧、适合人群,助你从 0…

作者头像 李华
网站建设 2026/4/16 13:58:58

MDSKSRS071-03伺服电机

MDSKSRS071-03 是三菱(Mitsubishi)系列的伺服电机型号,属于高性能交流伺服电机,通常配合伺服驱动器使用,用于精确位置、速度和扭矩控制的自动化系统。以下是详细信息整理:MDSKSRS071-03 伺服电机主要特点高…

作者头像 李华
网站建设 2026/4/16 13:59:00

3.抽象类、接口、内部类

抽象类、接口、内部类 一、抽象类为子类提供一个通用的模版和框架,定义一些通用的逻辑或规范,同时允许子类根据需要实现具体功能。1、抽象类不能被实例化。 2、抽象类应该至少有一个抽象方法,否则它没有任何意义。 3、抽象类中的抽象方法没有…

作者头像 李华
网站建设 2026/4/16 8:37:34

Kafka简介

kafka简介: Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的…

作者头像 李华