2010-01-21 63 views
5

是否有可能在C#中編寫一個簡單且快速的函數,該函數將執行字符串中的任意方法?例如,如果我設置了MyString =「MessageBox.Show(」Some Message「)」,然後調用ExecuteString(MyString),則會彈出一個消息框,其中包含「Some Message」。C#:執行存儲在字符串變量中的函數

(我可能已經在上面的代碼做一些錯誤我還不知道C#。我試圖評估它是否會爲一個特定的項目是適當的。)

+2

不知道這是一個重複的,但你可能會尋找一種方式來在C#REPL,並有一個很好的問題關於這裏:http://stackoverflow.com/questions/1038106/或在這裏http://stackoverflow.com/questions/2058715/它可能提供一些想法/源代碼。 – 2010-01-21 05:35:26

回答

2

唉, C#不是那種動態語言。你不能很容易地做到這一點,如果它真的是你需要做的事情,考慮使用更符合你需求的.Net語言,比如IronPython或IronRuby。

你最好的選擇是使用CodeDOM的命名空間,因爲這確實令人費解和憎惡從this forum thread顯示:

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}); 
      } 
     } 
    } 
} 
+0

你其實可以。我不僅發佈瞭如何,而且還自己做了。 – 2010-01-21 05:34:41

+1

我沒有說這不是_possible_,只是它不是_easy_。我不確定您提到的MSDN示例 - 需要超過100行來「執行」一行代碼,請注意 - 可以被認爲很容易。 – 2010-01-21 05:37:43

3

您應該能夠利用這一點,換到運行一個字符串轉換成所需的代碼一個函數。

基本上你在做的是將一小段C#代碼包裝在Program.Main樣式函數中,引用一些程序集的基本功能(可能包括你自己的程序集),然後在內存中運行已編譯的程序。

這可能比您需要運行一行或兩行代碼的開銷多一點。

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

+0

同意 - 最好的選擇是將這類工作委託給IronPython或IronRuby,這樣做更容易。 – 2010-01-21 05:36:02

+0

是的,對於如此少量的「腳本代碼」使用基於腳本的輕量級方法會更好。 – 2010-01-21 05:38:17

+0

如果需要上下文,例如從代碼字符串訪問主機應用程序中的運行時變量和類比IronPython或其他DLR語言好得多或者如果代碼字符串更改經常比編譯彙編不是一個好選擇,無論如何,因爲您將創建一個彙編每個需要評估的代碼字符串。 – affan 2010-01-21 05:43:10

相關問題