views:

293

answers:

2

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.)

A: 

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});
            }
        }
    }
}
John Feminella
You actually can. I've not only posted how, but also done it myself.
Nick Bedford
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.
John Feminella
+1  A: 

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

Nick Bedford
Agreed -- the best alternative is really to delegate this kind of work to IronPython or IronRuby, where it's much easier to do.
John Feminella
Yeah it would be better to use lightweight script-based methods for such small amounts of "script code".
Nick Bedford
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.
affan