Two possibilities:
- Reflection.Emit
- 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);
}
}
}