views:

121

answers:

3

I hold body of method in string. I want to create method dynamically. But I don't know, how to set its body. I saw very tedious way using CodeDom. And I saw using Emit with OpCodes. Is any way to use ready code from string variable?

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

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

this. __curious_geek
+1  A: 

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

drharris
Oh, thanks! There is the ready class for dynamic compilation in the article, which you refers to.Suffice it to write wwScripting lo_script = new wwScripting("CSharp"); lo_script.lSaveSourceCode = true; lo_script.AddAssembly("mscorlib.dll"); string result = (string)lo_script.ExecuteCode(method_body, new object[] { .../*params*/...});It's very convenient way.
greatromul
That way will work, but you should use that method only if you absolutely trust whatever input code is there. If some end user (or, perhaps some downloadable content) has the ability to run code, you should be very careful. Just an FYI so it doesn't bite you down the road.
drharris
+3  A: 

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();
Marc Gravell