greatromul
greatromul

Reputation: 1139

Is any simple way to create method and set its body dynamically in C#?

I have the body of a method stored as a string and I'm looking to create this method dynamically. However, I'm unsure how to assign its body. I've come across a rather complex method using CodeDom, and another using Emit with OpCodes. Is there a simpler way to utilize the existing code from a string variable?

string method_body = "return \"Hello, world!\";"; // there is a method body
DynamicMethod dm = new System.Reflection.Emit.DynamicMethod("My_method",
                 typeof(string), new Type[] { }); // some way to create method dynamically
// any way to set body?
string result = (string)dm.Invoke(...); // I need to write result in a variable

Upvotes: 5

Views: 3000

Answers (3)

Marc Gravell
Marc Gravell

Reputation: 1062800

It sounds like what you want is the "compiler as a service". That is not in MS .NET 4.0, but may be in a later release. It is already in Mono, though. Until then, the options available are:

  • use CSharpCodeProvider, but you'll have to load it in as a method (and create a delegate to it) via reflection
  • use CodeDom
  • use Reflection.Emit
  • use Expression

In 4.0, the Expression API is far richer than it was in 3.5, allowing most common constructs without the pain of CodeDom. But don't discount Reflection.Emit - it takes a little while to get your head around ILGenerator and using the stack, but it isn't as bad as people tend to think.

As a side-note, don't use Invoke from DynamicMethod unless you only want to execute it once. The better approach is to use CreateDelegate, then store (and re-use) that delegate:

var dm = new System.Reflection.Emit.DynamicMethod("My_method",
    typeof(string), null);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Hello, world!");
il.Emit(OpCodes.Ret);
Func<string> func = (Func<string>)dm.CreateDelegate(typeof(Func<string>));
var s = func();

Or with the Expression API:

var lambda =Expression.Lambda<Func<string>>(Expression.Constant("Hello, world"));
var func = lambda.Compile();
var s = func();

Upvotes: 7

drharris
drharris

Reputation: 11214

You need to take a look at these namespaces:

System.Reflection;
System.CodeDom.Compiler;
Microsoft.CSharp;

This may get you started: http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

Upvotes: 2

this. __curious_geek
this. __curious_geek

Reputation: 43207

Save this to a .CS file and compile and execute it on the fly.

Upvotes: 1

Related Questions