C#拦截/更改/重定向方法

假设我在第三方dll中有一个私有的,“实例”,非静态的bool方法。 所有这个方法都返回一个值。 没有其他的。 我将如何拦截对此方法的调用,更改它的IL OpCodes /方法体,或将其重定向到额外的,重写或派生的方法。

我不想反编译第三方DLL,手动更改源,并重新编译它。 我也不想将程序集保存到磁盘,因为这也涉及使用“重新编译”的程序集而不是原始程序集。

我基本上希望能够使用原始的dll – 没有替换或文件更改。 我只想做我上面提到的事情。

有没有办法解决这个问题? 如果是这样,你可以详细说明或发布参考/教程/等。

另外,我知道虚拟,覆盖和新的修饰符,但请记住我:没有所说的第三方dll的源,无法访问源,不想用dotPeek和重新编译等东西进行反编译。

谢谢!

编辑:我忘了提及基础架构的其余部分:MainProgram加载ThirdPartyDLL。 MainProgram还加载MyPluginDLL。 我正在尝试从MyPluginDLL更改ThirdPartyDLL中的方法,以便当MainProgram调用所述方法时,它将调用更改的方法。 我希望能够在不保存新assembly并使用新assembly重新启动MainProgram的情况下执行此操作。 基本上,我想在启动时或MainProgram运行时执行此操作。

下面是使用Mono Cecil更改内存中的程序集并在其上执行方法的代码示例。 请注意,修改和保存程序集非常慢。 这应该在您的应用程序启动时完成。

class Program { static void Main(string[] args) { Assembly assembly; using (MemoryStream assemblyStream = new MemoryStream(File.ReadAllBytes("TargetDLL.dll"))) { // 1. Get the reference to third-party method. AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(assemblyStream); TypeDefinition targetDLLType = assemblyDef.Modules[0].GetType("TargetDLL.Foo"); MethodDefinition barMethod = targetDLLType.Methods[0]; // 2. Let's see what Foo.Bar returns... assembly = Assembly.Load(assemblyStream.ToArray()); Console.WriteLine(CallMethod(assembly.GetType("TargetDLL.Foo"), "Bar")); // 3. Boot up the IL processor. var processor = barMethod.Body.GetILProcessor(); // 4 View the unmodified IL. Console.WriteLine("Original code"); PrintIL(processor); // 5. Modify the code. // 5.a Clear the method of all IL. processor.Body.Instructions.Clear(); // 5.b Inject our custom return value. processor.Emit(OpCodes.Ldc_I4, 1337); processor.Emit(OpCodes.Ret); // 6. And how does it look now? Console.WriteLine(); Console.WriteLine("New code"); PrintIL(processor); // 7. Save it. assemblyDef.Write(assemblyStream); assembly = Assembly.Load(assemblyStream.ToArray()); // 8. Result value. Console.WriteLine(CallMethod(assembly.GetType("TargetDLL.Foo"), "Bar")); } Console.WriteLine("END"); Console.ReadKey(true); } static void PrintIL(ILProcessor processor) { foreach (var instruction in processor.Body.Instructions) { Console.WriteLine(instruction); } } static T CallMethod(Type type, string method) { return (T)type.InvokeMember("Bar", BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public, null, null, null); } } 

在同一目录中添加名为TargetDLL.dll的以下DLL。 包含此代码:

 namespace TargetDLL { public static class Foo { public static int Bar() { return 0; } } } 

编辑

我认为你的错误与Mono.Cecil的版本有关。 我在GitHub的master分支上使用9.5.0 。 下载ZIP文件并根据需要构建项目。