2012-10-30 47 views
1

可能重複:
Is it possible to dynamically compile and execute C# code fragments?從文本文件在C#中執行代碼行

我有一個文本文件的樣子:

AssembleComponent Motor = new AssembleComponent; 
AssembleComponent Shaft = new AssembleComponent; 
...... 

Motor.cost = 100; 
Motor.quantity = 100; 
Shaft.cost = 10; 
Shaft.quantity = 100; 
...... 

我希望執行這些在C#中的代碼行,以便我將這些Motor.cost,Motor.quantity,Shaft.cost,Shaft.quantity變量存儲在內存中後來計算。

我能做些什麼來實現這一目標?

+0

可能重複:http://stackoverflow.com/q/826398/380384 – ja72

+0

這是不是一個真正的重複,因爲問題不從文件執行任意代碼行來解決。相反,只有值存儲在文件中,而不是代碼中。 –

回答

2

存儲爲XML,而不是

<?xml version="1.0" encoding="UTF-8"?> 
<Components> 
    <Component name="Motor" cost="100" quantity="100" /> 
    <Component name="Shaft" cost="10" quantity="100" /> 
</Components> 

假設你有這樣的定義

public class AssembleComponent 
{ 
    public decimal Cost { get; set; } 
    public int Quantity { get; set; } 
} 

裝載方法

var components = new Dictionary<string, AssembleComponent>(); 
XDocument doc = XDocument.Load(@"C:\Users\Oli\Desktop\components.xml"); 
foreach (XElement el in doc.Root.Descendants()) { 
    string name = el.Attribute("name").Value; 
    decimal cost = Decimal.Parse(el.Attribute("cost").Value); 
    int quantity = Int32.Parse(el.Attribute("quantity").Value); 
    components.Add(name, new AssembleComponent{ 
          Cost = cost, Quantity = quantity 
         }); 
} 

然後,您可以訪問諸如組件這

AssembleComponent motor = components["Motor"]; 
AssembleComponent shaft = components["Shaft"]; 

注:在運行時調用編譯器動態地創建變量名,因爲你需要在編譯時就知道他們(或設計時,如果你喜歡)做一些與他們有用不是很有用。因此,我將這些組件添加到字典中。這是動態創建「變量」的好方法。

+0

謝謝你的幫助。對不起,我沒有意識到這個功能,不及時接受你的答案:D。 – Anthony

0

你有兩個主要選擇:

  1. 展開文本,直到它變成合法的C#代碼,編譯並執行它
  2. 解析它,執行它自己(即它解釋)。
2

如果它只是數據不使用平面文本文件,但XML-代替。

可以反序列化的XML中的對象並對其進行必要的操作。

2

以下是我過去使用的一些代碼,大多數是您想要的,但您可能需要根據自己的具體需求來調整它。簡而言之,它執行以下操作:

  • 在該名稱空間中創建一個臨時名稱空間和一個公共靜態方法。
  • 將代碼編譯到內存中的程序集。
  • 提取編譯的方法,並把它變成一個代表。
  • 執行委託。

在這一點上,它就像執行一個普通的靜態方法,所以當你說你想在內存中的結果供以後使用時,你必須弄清楚它是如何工作的。

public void CompileAndExecute(string CodeBody) 
{ 
    // Create the compile unit 
    CodeCompileUnit ccu = CreateCode(CodeBody); 

    // Compile the code 
    CompilerParameters comp_params = new CompilerParameters(); 
    comp_params.GenerateExecutable = false; 
    comp_params.GenerateInMemory = true; 
    comp_params.TreatWarningsAsErrors = true; 
    comp_results = code_provider.CompileAssemblyFromDom(comp_params, ccu); 

    // CHECK COMPILATION RESULTS 
    if (!comp_results.Errors.HasErrors) 
    { 
     Type output_class_type = comp_results.CompiledAssembly.GetType("TestNamespace.TestClass"); 

     if (output_class_type != null)  
     {  
      MethodInfo compiled_method = output_class_type.GetMethod("TestMethod", BindingFlags.Static | BindingFlags.Public);  
      if (compiled_method != null)  
      {  
       Delgate created_delegate = Delegate.CreateDelegate(typeof(System.Windows.Forms.MethodInvoker), compiled_method); 
       if (created_delegate != null) 
       { 
        // Run the code 
        created_delegate.DynamicInvoke(); 
       } 
      } 
     } 
    } 
    else 
    { 
     foreach (CompilerError error in comp_results.Errors) 
     { 
      // report the error 
     } 
    } 
} 

public CodeCompileUnit CreateCode(string CodeBody) 
{ 
    CodeNamespace code_namespace = new CodeNamespace("TestNamespace"); 

    // add the class to the namespace, add using statements 
    CodeTypeDeclaration code_class = new CodeTypeDeclaration("TestClass"); 
    code_namespace.Types.Add(code_class); 
    code_namespace.Imports.Add(new CodeNamespaceImport("System")); 

    // set function details 
    CodeMemberMethod method = new CodeMemberMethod(); 
    method.Attributes = MemberAttributes.Public | MemberAttributes.Static; 
    method.ReturnType = new CodeTypeReference(typeof(void)); 
    method.Name = "TestMethod"; 

    // add the user typed code 
    method.Statements.Add(new CodeSnippetExpression(CodeBody)); 

    // add the method to the class 
    code_class.Members.Add(method); 

    // create a CodeCompileUnit to pass to our compiler 
    CodeCompileUnit ccu = new CodeCompileUnit(); 
    ccu.Namespaces.Add(code_namespace); 

    return ccu; 
}