.net 使用C动态编译代码#

.net 使用C动态编译代码#,.net,dynamic,c#-4.0,.net,Dynamic,C# 4.0,如何编写C代码来编译和运行动态生成的C代码。周围有例子吗 我想要的是动态构建一个C#类(或多个类),并在运行时运行它们。我希望生成的类与其他非动态的C#类交互 我见过生成exe或dll文件的示例。我不是在追求它,我只是想让它在内存中编译一些C代码,然后运行它。比如说, 这是一个非动态的类,它将在我的C#assembly中定义,并且只在编译时更改 public class NotDynamicClass { private readonly List<string> value

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

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

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

这是一个非动态的类,它将在我的C#assembly中定义,并且只在编译时更改

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
    }
}
结果是,在最后,我的非动态代码将调用ProcessValues,并执行其他一些操作。动态代码的要点是允许我们或客户机向软件添加自定义逻辑

谢谢。

有两种可能:


  • 更新:

    根据评论部分的要求,这里有一个完整的示例,演示如何使用Reflection.Emit动态构建类并向其中添加静态方法:

    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]);
        }
    }
    

    Mono有一个可以在Windows上的.NET应用程序中使用的插件(当然还有Linux)。

    编译“插件”程序集并在运行时加载这些插件而不是动态编译东西是否可行?是的,我以前在另一个项目中也这样做过。这是可能的,但并不是我们在这个项目上所追求的。我会考虑的,谢谢。你有什么好的例子可以和我想做的事情相对应吗?@彼得,请看我的更新。我添加了一个示例,演示了如何在运行时通过向类添加方法并在最后调用这些方法来动态构建类。谢谢。这就是我所害怕的,也是我在别处看到的。您正在使用GetILGenerator构建一个方法,并调用il.Emit等。难道没有办法只编写代码,指定一个包含代码的字符串,然后像上面的第二个代码示例那样说“runthat”吗。原因是我们想将这些脚本编写为“文本”并存储在数据库中。@peter,请查看我的第二次更新。添加了CodeDom编译器的示例。谢谢,非常好。那看起来太棒了。一点也不能怪这个!!
    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]);
        }
    }
    
    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);
            }
        }
    }