c# - Reflection.Emit.ILGenerator::Emit,从第三方.net 库调用方法

标签 c# .net compiler-construction reflection.emit

我正在尝试创建用于教育目的的简单 .net 编译器。在解析、扫描和构建 AST 之后,我正在使用 Reflection.Emit.ILGenerator 生成 .net 程序集。

这是我的程序集生成示例代码:

static void Main(string[] args)
{
    string moduleName = "Test.exe";

    AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(moduleName));
    AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName);
    TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", TypeAttributes.Public);
    MethodBuilder mainMethod = typeBuilder.DefineMethod(
        "Main", MethodAttributes.Public | MethodAttributes.Static, typeof(void), System.Type.EmptyTypes);


    ILGenerator il = mainMethod.GetILGenerator();

    il.Emit(OpCodes.Ldstr, "Test!");
    il.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new System.Type[] { typeof(string) }));
    il.Emit(OpCodes.Ret);

    typeBuilder.CreateType();
    moduleBuilder.CreateGlobalFunctions();
    assemblyBuilder.SetEntryPoint(mainMethod);
    assemblyBuilder.Save(moduleName);
}

一切正常,此代码生成具有以下类的可执行文件:

using System;

public class Program
{
    public Program()
    {
    }

    public static void Main()
    {
        Console.WriteLine("Test!");
    }
}

接下来,我将创建一个简单的第三方库,其中包含构建到 ThirdPartyLibrary.dll 的单个类:

using System;

namespace ThirdPartyLibrary
{
    public class MyPrint
    {
        public static void Print(string s)
        {
            Console.WriteLine("Third party prints: " + s);
        }
    }
}

现在我希望将 Console.WriteLine 方法调用替换为我的库中的 MyPrint.Print 方法调用,并获得如下结果代码:

using System;
using ThirdPartyLibrary;

public class Program
{
    public Program()
    {
    }

    public static void Main()
    {
        MyPrint.Print("Test!");
    }
}

据我所知,我必须阅读我的 ThirdPartyLibrary.dll 文件,然后以某种方式反射(reflect)它以从中获取所有类型,然后就可以使用 MyPrint类型。最后,我希望能够像使用 csc.exe 一样将引用路径作为 myCompiler.exe 参数。

所以问题是:

  • 怎么做?
  • 这一切如何命名? (我不明白要谷歌什么)
  • 也许我应该使用其他一些框架而不是 Reflection 来完成这一切?
  • 任何其他建议...

最佳答案

这里唯一的变化是目标方法:

var targetMethod = Assembly.LoadFrom("ThirdPartyLibrary.dll")
    .GetType("ThirdPartyLibrary.MyPrint")
    .GetMethod("Print", new [] {typeof(string)});
...
il.Emit(OpCodes.Ldstr, "Test!");
il.Emit(OpCodes.Call, targetMethod);
il.Emit(OpCodes.Ret);

因此,我们不使用 Console.WriteLine,而是调用 MyPrint.Print

  • 怎么做? A:如上
  • 这一切如何命名? A:IL 生成、元编程、反射
  • 也许我应该使用其他一些框架而不是 Reflection 来完成这一切? A:反射覆盖大部分场景;我在几个地方使用了 IKVM.Reflection.dll,因为它允许我进行跨框架定位,但您可能不需要它。您可能发现方便的是 Sigil ,它通过在生成时(而不是执行时)为您提供理智的错误报告,消除了 IL 生成(不平衡堆栈等)的许多痛苦。 Mono.Cecil 也很有趣

关于c# - Reflection.Emit.ILGenerator::Emit,从第三方.net 库调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16420498/

相关文章:

javascript - 在 C# 中使用 Socket.IO

c# - 可观察集合中的事务支持

.net - ORM 之于 RDBMS,就像 xxx 之于 OLAP 多维数据集? xxx存在吗?

c# - 基于 Active Directory 为网站开发登录页面

c# - 以正确的方式做干燥的事情

C++:const static DEBUG 和 if 语句,实际的执行时间开销是多少?

java - MinGW shell 未找到 MinGW gcj 编译器

c - 静态初始化变量(在编译时)

c# - 来自 NuGet 的 System.Data.SQLite,interop dll 未复制到输出目录

c# - 通用 Windows 项目 - HttpClient 异常