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

3

5

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
Decongestant answered 7/6, 2010 at 5:13 Comment(0)
B
2

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

Boding answered 7/6, 2010 at 5:17 Comment(2)
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.Decongestant
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.Boding
P
7

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();
Psychrometer answered 7/6, 2010 at 6:14 Comment(0)
B
2

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

Boding answered 7/6, 2010 at 5:17 Comment(2)
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.Decongestant
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.Boding
C
1

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

Colicroot answered 7/6, 2010 at 5:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.