Compiling code dynamically using C#

后端 未结 2 765
你的背包
你的背包 2020-12-09 06:40

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

What I am after is to dynamically build up a C# class (or classe

相关标签:
2条回答
  • 2020-12-09 07:06

    Two possibilities:

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

    UPDATE:

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

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


    UPDATE 2:

    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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-09 07:08

    Mono has a C# compiler as a service that's usable in .NET applications on Windows (along with Linux, of course).

    0 讨论(0)
提交回复
热议问题