[英]Execute code lines from a text file in 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 變量存儲在 memory 中以供以后計算。
我該怎么做才能實現這一目標?
而是將其存儲為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"];
注意:在運行時通過調用編譯器動態創建變量名不是很有用,因為您需要在編譯時(或設計時,如果願意)了解它們,以對它們進行有用的處理。 因此,我將組件添加到字典中。 這是動態創建“變量”的好方法。
您可以使用Microsoft.CSharp.CSharpCodeProvider
即時編譯代碼。
具體來說,看看CompileAssemblyFromFile 。
如果只是數據,請不要使用純文本文件,而應使用XML代替。
您可以將XML反序列化為對象並對其執行必要的操作。
這是我過去使用過的一些代碼,可以滿足您的大部分需求,盡管您可能需要對其進行調整以適應您的特定需求。 簡而言之,它執行以下操作:
那時,這就像執行普通的靜態方法一樣,因此當您說希望將結果保存在內存中以備后用時,您必須弄清楚它是如何工作的。
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;
}
您有兩個主要選擇:
這可以按照以下步驟完成: CodeGeneration
=> InMemory Compilation to Exe
==> Execution
。
您可以設計類似於這樣的結構:
public bool RunMain(string code)
{
const string CODE_NAMESPACE = "CompileOnFly";
const string CODE_CLASS = "Program";
const string CODE_METHOD = "Main";
try
{
var code_namespace = new CodeNamespace(CODE_NAMESPACE);
// add the class to the namespace, add using statements
var code_class = new CodeTypeDeclaration(CODE_CLASS);
code_namespace.Types.Add(code_class);
code_namespace.Imports.Add(new CodeNamespaceImport("System"));
// set function details
var method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
method.ReturnType = new CodeTypeReference(typeof(void));
method.Name = CODE_METHOD;
// add the user typed code
method.Statements.Add(new CodeSnippetExpression(code));
// add the method to the class
code_class.Members.Add(method);
// create a CodeCompileUnit to pass to our compiler
CodeCompileUnit code_compileUnit = new CodeCompileUnit();
code_compileUnit.Namespaces.Add(code_namespace);
var compilerParameters = new CompilerParameters();
compilerParameters.ReferencedAssemblies.Add("system.dll");
compilerParameters.GenerateExecutable = true;
compilerParameters.GenerateInMemory = true;
compilerParameters.TreatWarningsAsErrors = true;
var code_provider = CodeDomProvider.CreateProvider("CSharp");
var comp_results = code_provider.CompileAssemblyFromDom(compilerParameters, code_compileUnit);
if (comp_results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in comp_results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
//Get assembly, type and the Main method:
Assembly assembly = comp_results.CompiledAssembly;
Type program = assembly.GetType($"{CODE_NAMESPACE}.{CODE_CLASS}");
MethodInfo main = program.GetMethod(CODE_METHOD);
//runtit
main.Invoke(null, null);
return true;
}
catch(Exception compileException)
{
Console.Write(compileException.ToString());
return false;
}
}
在上面的代碼中,我們實際上創建了一個簡單的控制台Program.Main()
作為
namespace CompileOnFly
{
internal class Program
{
static void Main()
{
//<your code here>
}
}
}
在 memory 中,然后在 Memory 中將其編譯為可執行文件並執行。 但是Main()
主體//<your code here>
是通過參數code
動態添加到方法中的。
因此,如果您在文本文件script.txt
中有一個腳本,如下所示:
Console.Write("Write your name: ");
var name = Console.ReadLine();
Console.WriteLine("Happy new year 2023 " + name);
您可以簡單地閱讀所有文本並將其作為參數發送給它:
var code = File.ReadAllText(@"script.txt");
RunMain(code);
運行script.txt
文件中的語句。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.