使用Roslyn与.NET Core时,如何解决System.Windows.Forms命名空间不存在问题
我正在开发一个基于Roslyn的C#代码运行时编译系统,通过以下代码添加程序集引用(传入程序集完整文件名):
public bool AddAssembly(string assemblyDll) { if (string.IsNullOrEmpty(assemblyDll)) return false; var file = Path.GetFullPath(assemblyDll); if (!File.Exists(file)) { // 检查框架或专用运行时应用文件夹 var path = Path.GetDirectoryName(typeof(object).Assembly.Location); file = Path.Combine(path, assemblyDll); if (!File.Exists(file)) return false; } if (References.Any(r => r.FilePath == file)) return true; try { var reference = MetadataReference.CreateFromFile(file); References.Add(reference); } catch { return false; } return true; }
此前功能正常,但尝试编译WinForms窗体代码时,即便已添加System.Windows.Forms.dll程序集引用,仍报错:
Type or namespace name "Forms" does not exist in the namespace 'System.Windows'
查资料得知,在Visual Studio中需编辑.csproj文件添加以下配置解决:
<UseWindowsForms>true</UseWindowsForms>
请问如何让Roslyn识别我要使用WinForms窗体的需求?
解决方案
Roslyn编译WinForms代码时,仅添加程序集引用不够,还需要在编译配置中明确启用WinForms相关支持,对应Visual Studio里<UseWindowsForms>true</UseWindowsForms>的作用,具体操作如下:
设置编译输出类型为Windows应用
创建CSharpCompilation时,将OutputKind指定为WindowsApplication,这会告诉编译器生成WinForms兼容的可执行文件:var compilationOptions = new CSharpCompilationOptions(OutputKind.WindowsApplication);添加WinForms专属编译符号
通过定义WINDOWS_FORMS编译符号,让编译器启用WinForms相关的语法和类型支持:compilationOptions = compilationOptions.WithDefineSymbols("WINDOWS_FORMS");补全依赖程序集引用
除了System.Windows.Forms.dll,还需添加System.Drawing.dll(WinForms的核心依赖),确保引用的是对应.NET版本的正确路径(.NET Framework从GAC/框架目录获取,.NET 6+从运行时目录获取)。完整编译示例
整合上述配置的完整代码片段:// 解析WinForms代码为语法树 var syntaxTree = CSharpSyntaxTree.ParseText(@" using System.Windows.Forms; public class MyWinForm : Form { public MyWinForm() { Text = ""Roslyn WinForms Demo""; Size = new System.Drawing.Size(300, 200); } } "); // 配置编译选项 var compilationOptions = new CSharpCompilationOptions(OutputKind.WindowsApplication) .WithPlatform(Platform.AnyCpu) .WithDefineSymbols("WINDOWS_FORMS"); // 收集必要的程序集引用 var references = new List<MetadataReference> { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Form).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Drawing.Size).Assembly.Location) }; // 创建编译对象并执行编译 var compilation = CSharpCompilation.Create( "WinFormsDynamicAssembly", new[] { syntaxTree }, references, compilationOptions ); using var ms = new MemoryStream(); var emitResult = compilation.Emit(ms); if (!emitResult.Success) { // 输出编译错误 foreach (var error in emitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error)) { Console.WriteLine($"编译错误:{error.GetMessage()}"); } } else { // 加载编译后的程序集并运行窗体 ms.Seek(0, SeekOrigin.Begin); var assembly = Assembly.Load(ms.ToArray()); var formType = assembly.GetType("MyWinForm"); Application.Run((Form)Activator.CreateInstance(formType)); }
核心就是通过OutputKind.WindowsApplication和WINDOWS_FORMS符号,让Roslyn启用WinForms的编译支持,再配合完整的依赖引用,就能解决找不到System.Windows.Forms命名空间的问题。
内容的提问来源于stack exchange,提问作者Andy L

