使用 C# 动态编译代码 [英] Compiling code dynamically using C#

查看:18
本文介绍了使用 C# 动态编译代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何编写 C# 代码来编译和运行动态生成的 C# 代码.周围有例子吗?

How can I wrote C# code to compile and run dynamically generated C# code. Are there examples around?

我所追求的是动态构建一个 C# 类(或多个类)并在运行时运行它们.我希望生成的类与其他非动态的 C# 类交互.

What I am after is to dynamically build up a C# class (or classes) and run them at runtime. I want the generated class to interact with other C# classes that are not dynamic.

我见过生成 exe 或 dll 文件的示例.我不是在那之后,我只是想让它在内存中编译一些 C# 代码然后运行它.例如,

I have seen examples that generate exe or dll files. I am not after that, I just want it to compile some C# code in memory and then run it. For instance,

所以这里有一个不是动态的类,它将在我的 C# 程序集中定义,并且只会在编译时更改,

So here is a class which is not dynamic, it will be defined in my C# assembly and will only change at compile time,

public class NotDynamicClass
{
    private readonly List<string> values = new List<string>();

    public void AddValue(string value)
    {
        values.Add(value);
    }

    public void ProcessValues()
    {
        // do some other stuff with values
    }
}

这是我的动态类.我的 C# 代码会生成这个类并运行它,

Here is my class that is dynamic. My C# code will generate this class and run it,

public class DynamicClass
{
    public static void Main()
    {
        NotDynamicClass class = new NotDynamicClass();

        class.AddValue("One");
        class.AddValue("two");
    }
}

所以结果是最后我的非动态代码会调用 ProcessValues 并且它会做一些其他的事情.动态代码的意义在于允许我们或客户端向软件添加自定义逻辑.

So the result is that at the end my non dynamic code would call ProcessValues and it would do some other stuff. The point of the dynamic code is to allow us or the client to add custom logic to the software.

谢谢.

推荐答案

两种可能:

  1. Reflection.Emit
  2. System.CodeDom.Compiler

<小时>

更新:

作为评论部分的请求,这里有一个完整的示例,说明如何使用 Reflection.Emit 动态构建一个类并向其添加静态方法:

As request in the comments section here's a full example illustrating the usage of Reflection.Emit to dynamically build a class and add a static method to it:

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

public class NotDynamicClass
{
    private readonly List<string> values = new List<string>();

    public void AddValue(string value)
    {
        values.Add(value);
    }

    public void ProcessValues()
    {
        foreach (var item in values)
        {
            Console.WriteLine(item);
        }
    }
}

class Program
{
    public static void Main()
    {
        var assemblyName = new AssemblyName("DynamicAssemblyDemo");
        var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, false);
        var typeBuilder = moduleBuilder.DefineType("DynamicClass", TypeAttributes.Public);

        var methodBuilder = typeBuilder.DefineMethod(
            "Main",
            MethodAttributes.Public | MethodAttributes.Static,
            null,
            new Type[0]
        );

        var il = methodBuilder.GetILGenerator();
        var ctor = typeof(NotDynamicClass).GetConstructor(new Type[0]);
        var addValueMi = typeof(NotDynamicClass).GetMethod("AddValue");
        il.Emit(OpCodes.Newobj, ctor);
        il.Emit(OpCodes.Stloc_0);
        il.DeclareLocal(typeof(NotDynamicClass));
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ldstr, "One");
        il.Emit(OpCodes.Callvirt, addValueMi);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ldstr, "Two");
        il.Emit(OpCodes.Callvirt, addValueMi);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Callvirt, typeof(NotDynamicClass).GetMethod("ProcessValues"));
        il.Emit(OpCodes.Ret);
        var t = typeBuilder.CreateType();
        var mi = t.GetMethod("Main");
        mi.Invoke(null, new object[0]);
    }
}

您可以在非 NotDynamicClass 方法中放置断点,然后查看它们是如何被调用的.

You could put breakpoints inside your not NotDynamicClass methods and see how they get invoked.

更新 2:

以下是 CodeDom 编译器的示例:

Here's an example with CodeDom compiler:

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using Microsoft.CSharp;

public class NotDynamicClass
{
    private readonly List<string> values = new List<string>();

    public void AddValue(string value)
    {
        values.Add(value);
    }

    public void ProcessValues()
    {
        foreach (var item in values)
        {
            Console.WriteLine(item);
        }
    }
}

class Program
{
    public static void Main()
    {
        var provider = CSharpCodeProvider.CreateProvider("c#");
        var options = new CompilerParameters();
        var assemblyContainingNotDynamicClass = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
        options.ReferencedAssemblies.Add(assemblyContainingNotDynamicClass);
        var results = provider.CompileAssemblyFromSource(options, new[] 
        { 
@"public class DynamicClass
{
    public static void Main()
    {
        NotDynamicClass @class = new NotDynamicClass();
        @class.AddValue(""One"");
        @class.AddValue(""Two"");
        @class.ProcessValues();
    }
}"
        });
        if (results.Errors.Count > 0)
        {
            foreach (var error in results.Errors)
            {
                Console.WriteLine(error);
            }
        }
        else
        {
            var t = results.CompiledAssembly.GetType("DynamicClass");
            t.GetMethod("Main").Invoke(null, null);
        }
    }
}

这篇关于使用 C# 动态编译代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆