使用CSharpCodeProvider动态编译运行C#字符串代码时,如何访问当前项目窗体及类的控件
解决动态编译C#代码访问当前窗体成员的问题
我之前也踩过这个坑,用CSharpCodeProvider动态编译代码时,默认情况下动态生成的程序集和你的窗体类不在同一个上下文,而且没有办法直接访问当前窗体的实例,所以才会出现无法访问textBox1这类控件的情况。下面给你一套完整的解决方案:
核心思路
要让动态代码能访问当前窗体的成员,需要做到两点:
- 动态编译时引用当前项目的程序集,让动态代码能识别你的窗体类型
- 把当前窗体的实例传递给动态执行的代码,这样就能通过实例访问控件和成员
完整代码实现
private void btncompiler_Click(object sender, EventArgs e) { string str = @" using System; using System.Windows.Forms; public class DynamicCodeExecutor { public void Execute(YourFormType form) { // 这里可以直接通过form实例访问窗体的成员 int a = 3; int b = 5; // 注意控件操作要在UI线程,所以需要Invoke if (form.textBox1.InvokeRequired) { form.textBox1.Invoke(new Action(() => { form.textBox1.Text = (a + b).ToString(); })); } else { form.textBox1.Text = (a + b).ToString(); } } }"; // 1. 设置编译参数 var compilerParams = new CompilerParameters(); // 添加必要的程序集引用 compilerParams.ReferencedAssemblies.Add("System.dll"); compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll"); // 关键:引用当前项目的程序集,这样动态代码能识别你的窗体类型 compilerParams.ReferencedAssemblies.Add(System.Reflection.Assembly.GetExecutingAssembly().Location); // 生成内存中的程序集,不用写到磁盘 compilerParams.GenerateInMemory = true; // 2. 编译代码 var codeProvider = new Microsoft.CSharp.CSharpCodeProvider(); CompilerResults results = codeProvider.CompileAssemblyFromSource(compilerParams, str); // 3. 检查编译错误 if (results.Errors.HasErrors) { StringBuilder errorMsg = new StringBuilder(); foreach (CompilerError error in results.Errors) { errorMsg.AppendLine($"错误行{error.Line}: {error.ErrorText}"); } MessageBox.Show(errorMsg.ToString()); return; } // 4. 加载编译后的程序集并执行代码 Assembly assembly = results.CompiledAssembly; Type executorType = assembly.GetType("DynamicCodeExecutor"); object executorInstance = Activator.CreateInstance(executorType); // 关键:把当前窗体实例传递给动态方法 executorType.GetMethod("Execute").Invoke(executorInstance, new object[] { this }); }
关键细节说明
- 替换
YourFormType:把代码里的YourFormType换成你实际的窗体类名(比如你的窗体叫MainForm,就改成MainForm) - 引用当前程序集:通过
System.Reflection.Assembly.GetExecutingAssembly().Location获取当前项目的程序集路径,添加到引用中,这样动态代码就能识别你的窗体类型 - 传递窗体实例:动态方法
Execute接收窗体实例参数,通过这个实例就能访问窗体上的所有控件和成员 - UI线程安全:因为动态代码可能在非UI线程执行,所以操作控件时要判断
InvokeRequired,确保在UI线程更新控件
额外提示
如果你的动态代码需要访问更多类成员,只需要在Execute方法里通过传递的窗体实例直接调用即可,比如form.YourCustomMethod()或者form.YourPublicProperty。
内容的提问来源于stack exchange,提问作者ame teaser
相关产品推荐
相关产品推荐

