C#: execute a function stored in a string variable
Asked Answered
C

3

5

Is it possible to write a simple and fast function in C# that will execute arbitrary methods from a string? For example, if I set MyString="MessageBox.Show("Some Message")" and then call ExecuteString(MyString), a message box would pop up with "Some Message" in it.

(I've probably made some sort of error in the above code. I don't yet know C#; I'm trying to evaluate whether it would be appropriate for a specific project.)

Codification answered 21/1, 2010 at 5:29 Comment(1)
Not sure if this is a duplicate, but you're likely looking for a way to to REPL in C#, and there is a good question about that here: stackoverflow.com/questions/1038106 or here stackoverflow.com/questions/2058715 which may offer some ideas/source code.Meenen
N
3

You should be able to use this and wrap the code required to run a string into a function.

Essentially what you're doing is wrapping the small bit of C# code in a Program.Mainstyle function, referencing some assemblies for basic functionality (maybe including your own assembly) then run the compiled program in memory.

It's likely a bit of more overhead than you need to simply run one or two lines of code mind you.

http://support.microsoft.com/kb/304655

Noiseless answered 21/1, 2010 at 5:33 Comment(3)
Agreed -- the best alternative is really to delegate this kind of work to IronPython or IronRuby, where it's much easier to do.Gi
Yeah it would be better to use lightweight script-based methods for such small amounts of "script code".Noiseless
If a context is required e.g access to runtime variables and classes in host application from the code string than ironPython or other DLR languages is much better Or if the code string changes often than compile assembly is not a good option anyway as you will creating a assembly for each code string that need evaluation.Martinmas
B
3

what you appear to be looking for is CS-Script

Bowdlerize answered 10/8, 2011 at 13:52 Comment(0)
G
2

Alas, C# is not a dynamic language in that way. You can't really do this easily, and if it's really something you need to do, consider using a .Net language more in line with your needs, like IronPython or IronRuby.

Your best available alternative is to use the CodeDom namespace, as this truly convoluted and heinous example from this forum thread shows:

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Windows.Forms;

namespace TestApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        SampleLib.SampleType test = new SampleLib.SampleType();

        private void button1_Click(object sender, EventArgs e)
        {
            // Dynamically build and call the method
            label1.Text = test.MyText;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            StringBuilder DynamicCode = new StringBuilder();
            DynamicCode.Append("namespace TestDynamic");
            DynamicCode.Append("{");
            DynamicCode.Append("public class DynamicCode");
            DynamicCode.Append("{");
            DynamicCode.Append("public static void EditText(SampleLib.SampleType t)");
            DynamicCode.Append("{");
            DynamicCode.Append("t.MyText = \"Goodbye!\";");
            DynamicCode.Append("}");
            DynamicCode.Append("}");
            DynamicCode.Append("}");

            string CodeString = DynamicCode.ToString();

            System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
            CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
            CompilerParameters CompileParams = new CompilerParameters(new string[] { fi.DirectoryName + "\\SampleLib.dll" },
                fi.DirectoryName + "\\Dynamic.dll");
            CompileParams.MainClass = "DynamicCode";
            CompileParams.GenerateExecutable = false;
            //CompileParams.GenerateInMemory = true;
            CompilerResults r = provider.CompileAssemblyFromSource(CompileParams, new string[] {CodeString});
            foreach (CompilerError er in r.Errors)
            {
                Console.WriteLine(er.ErrorText);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            // Dynamically call assembly
            System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
            Assembly dynAsm = Assembly.LoadFile(fi.DirectoryName + "\\Dynamic.dll");
            if (dynAsm != null)
            {
                object o = dynAsm.CreateInstance("TestDynamic.DynamicCode", true);
                Type t = dynAsm.GetType("TestDynamic.DynamicCode");
                t.GetMethod("EditText").Invoke(o, new object[]{test});
            }
        }
    }
}
Gi answered 21/1, 2010 at 5:31 Comment(2)
You actually can. I've not only posted how, but also done it myself.Noiseless
I didn't say it wasn't possible, just that it wasn't easy. I'm not sure that the MSDN example you mention -- which requires over 100 lines to "execute" a single line of code, mind you -- could be considered easy.Gi

© 2022 - 2024 — McMap. All rights reserved.