如何用C#向目标DLL注入Mock类并实现自动化?
最佳实现方案
针对你需要在MyApp.exe运行前注入Mock版MyDep的需求,最实用的方案分为以下两类,按推荐优先级排序:
1. 运行时代码拦截(推荐使用Harmony框架)
无需修改原DLL,通过拦截MyClass中Dep字段的初始化逻辑,在运行时替换为Mock实例,是最灵活且无侵入的方案。
实现步骤:
- 新建一个C#控制台项目作为启动器(代替直接启动
MyApp.exe) - 安装NuGet包
Lib.Harmony - 定义Mock类(需实现原DLL中的
IMyDep接口):
public class MockMyDep : IMyDep { public void aMethod() { // 自定义Mock逻辑 Console.WriteLine("Mocked aMethod executed"); } }
- 在启动器中编写拦截与启动逻辑:
using HarmonyLib; using System.Diagnostics; using System.Reflection; class Program { static void Main(string[] args) { // 初始化Harmony实例,传入唯一标识 var harmony = new Harmony("com.your.mock.injector"); // 加载原依赖DLL,获取MyClass类型 var targetAssembly = Assembly.LoadFrom(@"path\to\your\original.dll"); var myClassType = targetAssembly.GetType("MyClass"); // 拦截MyClass的无参构造方法,在构造完成后替换Dep字段 var ctor = myClassType.GetConstructor(Type.EmptyTypes); harmony.Patch(ctor, postfix: new HarmonyMethod(typeof(MyClassPatch).GetMethod(nameof(MyClassPatch.Postfix)))); // 启动目标程序MyApp.exe Process.Start(@"path\to\MyApp.exe"); } } static class MyClassPatch { // 构造方法执行后的后置补丁 public static void Postfix(MyClass __instance) { // 将原Dep字段替换为Mock实例 __instance.Dep = new MockMyDep(); } }
注意:启动器项目需要引用原DLL,确保
IMyDep、MyClass等类型可访问;若原DLL未公开这些类型,可通过反射操作字段。
2. 离线修改原DLL的IL代码
通过操作IL指令,直接修改原DLL中MyClass初始化Dep字段的逻辑,替换为Mock类的实例化。适合不希望依赖第三方框架的场景。
实现步骤:
- 安装NuGet包
Mono.Cecil(用于解析和修改IL) - 编写DLL修改与启动代码:
using Mono.Cecil; using System; using System.Linq; using System.Diagnostics; class DllPatcher { static void Main(string[] args) { // 加载原DLL var assembly = AssemblyDefinition.ReadAssembly(@"path\to\your\original.dll"); var module = assembly.MainModule; // 获取原DLL中的MyClass类型 var myClassType = module.Types.First(t => t.Name == "MyClass"); // 引入Mock类的类型引用 var mockType = typeof(MockMyDep); var mockTypeRef = module.ImportReference(mockType); // 找到MyClass的无参构造方法 var ctor = myClassType.Methods.First(m => m.IsConstructor && !m.IsStatic); var ilProcessor = ctor.Body.GetILProcessor(); // 遍历IL指令,替换newobj MyDep为newobj MockMyDep foreach (var instr in ctor.Body.Instructions) { if (instr.OpCode == OpCodes.Newobj && instr.Operand is MethodReference mr && mr.DeclaringType.Name == "MyDep") { // 引入Mock类的无参构造方法引用 var mockCtorRef = module.ImportReference(mockType.GetConstructor(Type.EmptyTypes)); instr.Operand = mockCtorRef; break; } } // 保存修改后的DLL(可覆盖原文件或保存为新文件) assembly.Write(@"path\to\modified.dll"); // 启动MyApp.exe(确保它加载修改后的DLL) Process.Start(@"path\to\MyApp.exe"); } } // 必须与原IMyDep接口签名完全一致 public class MockMyDep : IMyDep { public void aMethod() { // Mock逻辑 } }
注意:若原DLL带有强签名,修改后需要用原密钥重新签名;需确保Mock类的命名空间、接口实现与原
MyDep完全匹配。
3. 直接替换原DLL类(不推荐)
若原DLL无强签名,可创建与原MyDep同名同命名空间的类,编译成DLL后替换原文件。但该方案灵活性极低,若原DLL中MyDep有其他内部依赖,极易引发运行错误。
内容的提问来源于stack exchange,提问作者Axeltherabbit
相关产品推荐
相关产品推荐

