2013-08-02 45 views
0

我想讓用戶寫一段代碼作爲文本,在飛行中編譯它,在我從數據源獲得的集合上執行它並獲得結果。如何將通用列表傳遞給動態編譯的C#代碼?

我一直在綁定將通用列表作爲參數傳遞給動態編譯的代碼,但我找不到一種方法。以下是我的代碼:

//User writes this code in a textbox and executes 
var executeCode = @"//this line doesn't work because I don't know the type 
          MessageBox.Show(Parameters[0].Count()); 
          //following works fine 
          var t = new List<string>{""asd"", ""xyz""}; 
          var a = t.Select(x => x).First(); 
          MessageBox.Show(a); 
          return (object) a;"; 

#region template Code 
executeCode = @" 
       using System; 
       using System.IO; 
       using System.Windows.Forms; 
       using System.Linq; 
       using System.Collections.Generic; 

       namespace MyNamespace { 
       public class MyClass { 

       public object DynamicCode(params object[] Parameters) { 
       " + executeCode + 
       "} } }"; 
#endregion template Code 

var references = new[] { "System.dll", "System.Core.dll", "System.Windows.Forms.dll" }; 

var compilerParams = new CompilerParameters 
      { 
       GenerateInMemory = true, 
       TreatWarningsAsErrors = false, 
       GenerateExecutable = false, 
       CompilerOptions = "/optimize" 
      }; 
     compilerParams.ReferencedAssemblies.AddRange(references); 

     var provider = new CSharpCodeProvider(); 
     var compile = provider.CompileAssemblyFromSource(compilerParams, executeCode); 

     if (compile.Errors.HasErrors) 
     { 
      var text = compile.Errors.Cast<CompilerError>() 
           .Aggregate("Compile Error: ", (current, ce) => current + ("rn" + ce.ToString())); 
      throw new Exception(text); 
     } 

     // execute the compiled code 

     var assembly = compile.CompiledAssembly; 
     var myObject = assembly.CreateInstance("MyNamespace.MyClass"); 
     if (myObject == null) 
     { 
      MessageBox.Show("Couldn't load class."); 
      return; 
     } 

     var sampleList = new List<string> { "abcd", "bcd" }; 
     var codeParams = new object[] { sampleList }; 

     try 
     { 
      var loResult = myObject.GetType().InvokeMember("DynamicCode",BindingFlags.InvokeMethod, null, myObject, codeParams); 
      MessageBox.Show("Method Call Result:\r\n\r\n" + loResult, "Compiler Demo", MessageBoxButtons.OK, MessageBoxIcon.Information); 
     } 
     catch (Exception loError) 
     { 
      MessageBox.Show(loError.Message, "Compiler Demo", MessageBoxButtons.OK, MessageBoxIcon.Information); 
     } 

在上面的代碼,我傳遞一個字符串列表。但是我會用一個對象替換它。用戶將編寫Linq查詢來過濾集合,我即時編譯並返回結果。

對此的任何指針都會非常有幫助。 (我使用C#4.5)

+0

你真的不得不以這種難以管理的方式編碼嗎?有一種叫做「接口」的東西,它是幾十年前發明的。 – zsong

+0

@sza這是我的臨時代碼。我將修復可管理性部分,如果它達到目的......否則爲什麼要刮更多代碼? – Amit

+0

你正試圖調用'.Count()',這樣你就可以立刻向下向'IEnumerable '下調 - 不管實際的類是什麼。 – millimoose

回答

2

有幾種選擇。

  1. 將參數對象的類型更改爲List<string>[]。如果你總是知道你正在通過List<string>,那麼這就是要走的路。

  2. 投射在您的動態生成的代碼中:((List<string)Parameters[0]).Count;這是一個有點笨重,但會擺脫錯誤。

  3. 將參數對象的類型更改爲dynamic。由於您在運行時編譯代碼,因此編譯時類型檢查可能不是您的優先考慮事項。

+0

我使用瞭解決方案1.我知道我傳入方法的類型,所以我總是將參數轉換爲特定的類型。 – Amit

相關問題