Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I use the CSharpCodeProvider to execute C# code from a string. But of course it creates a class for the code to run. Is there a way to call a method from the current app it is called from? For eg to call
CallTest()
from a parsed script in this (pseudo) example code
public class Test {
// lot of code
private void CallTest() {
Console.WriteLine("CallTest()");
public object OnMethodInvoke(string functionName, List<object> parameters) {
// lot of if statements
if(functionName == "exec") {
CSharpCodeProvider c = new CSharpCodeProvider();
ICodeCompiler icc = c.CreateCompiler();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
System.Text.StringBuilder sb = new System.Text.StringBuilder("");
sb.Append("using System;\n");
sb.Append("namespace ScriptStack.Dynamic {\n");
sb.Append("public class Code {\n");
sb.Append("public object EvalCode(){\n");
sb.Append((string)parameters[0]);
sb.Append("}\n");
sb.Append("}\n");
sb.Append("}\n");
CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0) return null;
System.Reflection.Assembly a = cr.CompiledAssembly;
object o = a.CreateInstance("ScriptStack.Dynamic.Code");
MethodInfo mi = o.GetType().GetMethod("EvalCode");
return mi.Invoke(o, null);
–
If I got your problem statement correctly, you want to be able to compile a statement like
t.CallTest(); //where t is an instance of your class
and run it.
As I hinted in the comments, Reflection might be way easier to do. But for a second, let's imagine you need to keep pressing on and generate some fancy code that you will then need to run (which is where LINQ Expression trees might be a better answer, but never mind - suppose we're still sticking to CodeDom).
There are a couple of issues I see to overcome here:
The unit of compilation in CodeDom is assembly, I don't believe you can have assembly nested in a class. Therefore you need to define at least a namespace and a class (which you seem to have done already)
I also don't believe CodeDom allows you to compile partial classes, therefore your generated code with direct references to Test
will not compile even if you manage to overcome point #1
With the above in mind, I believe one option will be to basically have your generated code invoke reflection to obtain a reference to your desired method and invoke it dynamically (which kinda gets reduced to my suggestion #1):
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;
namespace ConsoleApp9
public class MainTestClass
private void CallTest(string value) => Console.WriteLine($"CallTest({value})");
public object OnMethodInvoke(string functionName, List<object> parameters)
if (functionName == "exec")
CSharpCodeProvider c = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("ConsoleApp9.exe"); // note a reference to your main assembly here
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder("");
sb.Append("using System;\n");
sb.Append("using System.Reflection;\n");
sb.Append("using ConsoleApp9;\n"); // reference your main assembly ConsoleApp9. this is my test console app
sb.Append("namespace ScriptStack.Dynamic\n");
sb.Append("{\n");
sb.Append(" public class Code\n");
sb.Append(" {\n");
sb.Append(" private MainTestClass t;\n"); // reference your
sb.Append(" public Code(MainTestClass t) { this.t = t; }\n"); // we're going to capture reference to calling MainTestClass instance and use it for reflection
sb.Append(" public object EvalCode()\n");
sb.Append(" {\n");
sb.Append(" // this is a very standard method of invoking private methods. see this SO answer: https://stackoverflow.com/a/135482/12339804 \n");
sb.Append(" var mi = typeof(MainTestClass).GetMethod(\"CallTest\", BindingFlags.NonPublic | BindingFlags.Instance);\n");
sb.Append(" return mi.Invoke(t, new object[]{ \"" + (string)parameters[0] + "\" });\n"); //suppose you want to pass a string to your generated C# source.
sb.Append(" }\n");
sb.Append(" }\n");
sb.Append("}\n");
var cr = c.CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0) return null;
var a = cr.CompiledAssembly;
object o = a.CreateInstance("ScriptStack.Dynamic.Code", false, BindingFlags.Default, null, new object[] { this }, CultureInfo.InvariantCulture, null); //we have to opt for a way more overloaded CreateInstance method due to us requiring to pass a this into the Code class we're instantiating
var mi = o.GetType().GetMethod("EvalCode");
return mi.Invoke(o, null);
throw new NotImplementedException();
class Program
static void Main(string[] args)
var t = new MainTestClass();
t.OnMethodInvoke("exec", new List<object> { "parameter 1" });
Console.ReadKey();
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.