2011-05-12 19 views
1

我想要做的是允許用戶在文本框中編寫一個方法,並讓我的代碼調用該方法。給定目標函數,這最終將用於演示小程序中進行優化。C#編譯用戶提供的代碼和使用

所以我一直在使用示例控制檯應用程序,但我遇到了麻煩。我已經檢查了堆棧溢出和codeproject以及其他來源,並且已經到了可以編譯代碼的地步。但我迷失在如何調用它,只能訪問一個方法。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.CodeDom.Compiler; 
using Microsoft.CSharp; 
using System.Reflection; 

namespace CodeCompilerTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp"); 

      CompilerParameters parameters = new CompilerParameters(); 
      //parameters.GenerateExecutable = false; 
      parameters.GenerateInMemory = true; 
      //parameters.OutputAssembly = "Output.dll"; 

      string SourceString = @" 
            using System; 
            using System.Collections.Generic; 
            using System.Text; 

            namespace testone 
            { 
             public class myclass 
             { 
              public double Main() 
              { 
               return testd(5,8); 
              } 

              public double testd(double a, double b) 
              { 
               return a+b; 
              } 
             } 
            }"; 

      CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, SourceString); 

      if (results.Errors.Count > 0) 
      { 
       foreach (CompilerError CompErr in results.Errors) 
       { 
        Console.WriteLine("Line number " + CompErr.Line + ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + ";"); 
       } 
       Console.ReadLine(); 
      } 

      Assembly mAssembly = results.CompiledAssembly; 
      Type scripttype = mAssembly.GetType("myclass"); 
      Object rslt = new Object(); 
      Object[] argin = {5, 8}; 
      //rslt = scripttype.GetMethod("Main").Invoke(null, null); 
      rslt = scripttype.InvokeMember("Main", BindingFlags.InvokeMethod | BindingFlags.Public |BindingFlags.Static, null, null, null); 
      Console.WriteLine(((double)rslt).ToString()); 
      Console.ReadLine(); 
     } 
    } 
} 

我試過不同的組合,關於如何在方法上調用Invoke並不斷收到錯誤。 我希望能夠做的是讓用戶像這樣定義一個函數:

public double funcname(double x, double y) 
{ 
    return x+y; 
} 

然後我可以直接調用funcname的。 如果這是不可行的,我會採取我現在可以得到的。

任何幫助或指導,將不勝感激。 謝謝。

回答

1

您需要在GetType調用中包含名稱空間。
(或從源代碼中刪除名稱空間)

您可能更願意致電GetTypes()並查看程序集中定義的所有類型。

+0

工作,這樣可以讓我打電話給使用Invoke方法的功能。你知道一種叫做「testd(5,8)」的方法嗎?最終的希望是用戶提供的函數作爲dll的代表。 – 2011-05-12 16:22:14

+0

另一個有用的資源,或多或少說同一件事:http://stackoverflow.com/questions/1698870/accessing-class-and-function-after-compiling-compiledassembly – 2011-05-12 16:23:03

+0

@Tim:調用'GetTypes()'並找到一種具有您正在尋找的功能的類型。 – SLaks 2011-05-12 16:25:10

1

我相信這篇文章將幫助您直接通過使用接口 http://www.codeproject.com/Articles/26312/Dynamic-Code-Integration-with-CodeDom

也許下面的訪問方法是沒有直接關係到你的要求,但我相信,你需要使用激活創建的實例該類,所以你可以調用testd方法 我的意思是你定義的代碼沒有對象,只是類的定義。
此外,我用GetTypes()[0]因爲GetType()並沒有爲我

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.CodeDom.Compiler; 
using Microsoft.CSharp; 
using System.Reflection; 

namespace CodeCompilerTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp"); 

      CompilerParameters parameters = new CompilerParameters(); 
      //parameters.GenerateExecutable = false; 
      parameters.GenerateInMemory = true; 
      //parameters.OutputAssembly = "Output.dll"; 

      string SourceString = @" 
            using System; 
            using System.Collections.Generic; 
            using System.Text; 

            namespace testone 
            { 
             public class myclass 
             { 
              public double testd(double a, double b) 
              { 
               return a+b; 
              } 
             } 
            }"; 

      CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, SourceString); 

      if (results.Errors.Count > 0) 
      { 
       foreach (CompilerError CompErr in results.Errors) 
       { 
        Console.WriteLine("Line number " + CompErr.Line + ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + ";"); 
       } 
       Console.ReadLine(); 
      } 

      Assembly mAssembly = results.CompiledAssembly; 
      Type scripttype = mAssembly.GetTypes()[0]; 
      Object myObject = Activator.CreateInstance(scripttype); 
      double rsltd = 0.0; 
      Object[] argin = { 5.0, 8.0 }; 
      rsltd =(double) scripttype.GetMethod("testd").Invoke(myObject,argin); 
      // object rslt = new object(); 
      // rslt = scripttype.InvokeMember("testd", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, null); 
     Console.WriteLine(rsltd.ToString()); 
     Console.ReadLine(); 
     } 
    } 
}