Compiling code dynamically using C #

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

I want to dynamically create 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.

I saw examples that generate exe or dll files. I'm not after that, I just want it to compile some C # code in memory, and then run it. For example,

So here is a class that 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 } } 

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

So, as a result, my non-dynamic code will call ProcessValues, and it will do some other things. The dynamic code point allows us or the client to add custom logic to the software.

Thanks.

+7
source share
2 answers

Two possibilities:


UPDATE:

As a request, in the comments section, here is a complete example illustrating the use of Reflection.Emit to dynamically assemble 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 can set breakpoints inside your NotDynamicClass methods and see how they are called.


UPDATE 2:

Here is an example with the 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); } } } 
+15
source

Mono has a C # compiler as a service that can be used in .NET applications on Windows (of course, Linux).

+2
source

All Articles