在当前窗体(代码)的上下文中从字符串动态运行 C# 代码



我需要在当前表单(代码(的上下文中从文本文件运行代码。其中一个要求是让代码创建并向当前窗体添加新控件。

例如,在Form1.cs

using System.Windows.Forms;
...
public int[] someCoords = { 20, 10 };
public string someImportantString = "Hello";
public void SayHello() {
MessageBox.Show("Hello world.");
}
private void runCodeInForm() {
// theCode will be read from a text file
string theCode = @"
// Has System.Windows.Forms already added in form
Button newButton = new Button();
newButton.Text = someImportantString; // Hello
newButton.Location = new Point(someCoords[0], someCoords[1]); // 20, 10
// Add this button to the current form
this.Controls.Add(newButton);
this.SayHello(); // Says hello. Just an example function.
";
// Execute theCode in the current form
CodeRunner.Execute(theCode, this);
}

我尝试过使用CSharpCodeProvider,但这似乎只能将代码编译为单独的程序。

我想要这个,因为我希望用户能够将此代码(文本文件(更改为他们想要的内容。它不仅专门用于创建控件,而且需要该功能。

我不担心程序的安全性。

请考虑以下几点来解决问题:

  • 应将动态代码创建为 dll 中的类。
  • 您的类应该实现特定的接口或具有已知的方法,如Run.因此,您可以稍后在代码编译时调用该方法。
  • 您的类或已知方法应接受一些参数来接收上下文变量。这些上下文变量可以包含Form作为参数。您还可以将上下文参数封装在类/接口中,或者为了简单起见,您可以依靠dynamic来传递参数。

然后,若要运行动态代码,请先对其进行编译,然后将上下文参数传递给类或已知方法并调用已知方法。

下面是一个快速而脏的示例,说明如何在运行时编译和运行代码,并让代码使用您的上下文:

public string SomePublicField = "Hello!";
private void button1_Click(object sender, EventArgs e) {
var csc = new CSharpCodeProvider();
var parameters = new CompilerParameters(new[] {
"mscorlib.dll",
"System.Windows.Forms.dll",
"System.dll",
"System.Drawing.dll",
"System.Core.dll",
"Microsoft.CSharp.dll"});
var results = csc.CompileAssemblyFromSource(parameters,
@"
using System.Windows.Forms;
using System.Drawing;
public class Sample 
{
public void DoSomething (dynamic form) 
{
var b = new Button();
b.Text = form.Text;
b.Click += (s,e)=>{MessageBox.Show(form.SomePublicField);};
form.Controls.Add(b);
}
}");
//Check if compilation is successful, run the code
if (!results.Errors.HasErrors) {
var t = results.CompiledAssembly.GetType("Sample");
dynamic o = Activator.CreateInstance(t);
o.DoSomething(this);
}
else {
var errors = string.Join(Environment.NewLine,
results.Errors.Cast<CompilerError>().Select(x => x.ErrorText));
MessageBox.Show(errors);
}
}

基本上,您似乎想要做的是动态编译并将代码添加到当前程序中。这并非不可能,有多种方法可以做到这一点。

此类功能最常见的用途是插件和脚本系统。但是,这两者都有警告。

最大的缺点之一是,要运行已编译的代码(无论您正在这样做(,您需要使用标准的 Load 方法将其作为程序集加载到应用程序域中。加载库后,您实际上无法在不卸载应用程序域的情况下卸载它,因此这在某些情况下会产生问题。

如果这是您所追求的脚本,我会认真考虑使用预构建的脚本库(并且有很多(。有些人使用漂亮的技巧来使这项工作做好,并为您做了很多艰苦的工作......举个例子 http://csscript.net/

但是要做好准备! 插件和脚本系统开始时很容易,但它们非常繁琐,无法使稳定和可行。我建议先探索你的问题领域,并确保你没有试图重新发明轮子......有许多选项可以在运行时安全地序列化和加载对象参数,而无需大惊小怪

祝你好运

相关内容

最新更新