如何用Roslyn获取解决方案中的.shproj Shared Project并修改?
解决Roslyn无法识别并修改.shproj共享项目的问题
Roslyn的MSBuildWorkspace默认仅加载与特定编程语言关联的项目(如.csproj、.vbproj),而.shproj(共享项目)本质是一个代码共享容器,本身不参与编译,也没有关联的语言服务,因此直接通过Roslyn加载会抛出“扩展名未关联语言”的错误。
解决方案:间接操作共享项目的代码
共享项目的代码最终会被引用它的“宿主项目”(如普通C#项目)包含编译,因此可以通过以下两种方式操作:
1. 直接解析并修改.shproj文件
利用MSBuild的API直接读取和编辑.shproj的项目内容,因为它本质是标准的MSBuild项目文件。
示例代码:
using Microsoft.Build.Evaluation; using System.IO; using System.Linq; // 加载共享项目 string shprojPath = @"C:\Repo\Shared.shproj"; var projectCollection = new ProjectCollection(); var sharedProject = projectCollection.LoadProject(shprojPath); // 添加新的类文件到共享项目 string newClassFileName = "NewSharedClass.cs"; sharedProject.AddItem("Compile", newClassFileName); // 保存修改 sharedProject.Save(); // 写入新类的内容 string sharedProjectDir = Path.GetDirectoryName(shprojPath); string newClassPath = Path.Combine(sharedProjectDir, newClassFileName); string classContent = @"namespace ProjectX.Shared { public class NewSharedClass { // 自定义内容 } }"; File.WriteAllText(newClassPath, classContent);
2. 通过引用共享项目的宿主项目间接操作
如果需要使用Roslyn的语法分析、重构等功能,可以打开引用该共享项目的宿主项目,通过宿主项目访问共享项目的代码文件,再进行修改。
示例代码:
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.MSBuild; using Microsoft.Build.Locator; using System.IO; using System.Linq; using System.Threading.Tasks; // 初始化Roslyn MSBuildLocator.RegisterDefaults(); var workspace = MSBuildWorkspace.Create(); // 打开引用共享项目的宿主项目 string targetCsprojPath = @"C:\Repo\ProjectX.csproj"; var targetProject = await workspace.OpenProjectAsync(targetCsprojPath); // 指定共享项目的目录 string sharedProjectDir = @"C:\Repo\Shared"; // 创建新的类文件 string newClassPath = Path.Combine(sharedProjectDir, "NewSharedClass.cs"); var newClassText = SourceText.From(@"namespace ProjectX.Shared { public class NewSharedClass { // 类内容 } }"); // 将新文件添加到解决方案中,Roslyn会自动识别共享项目关联 var updatedSolution = targetProject.Solution.AddDocument( Path.GetFileName(newClassPath), newClassText, filePath: newClassPath ); // 应用修改到Workspace await workspace.TryApplyChanges(updatedSolution); // 同步更新.shproj文件,确保共享项目能识别新文件 var projectCollection = new ProjectCollection(); var sharedProject = projectCollection.LoadProject(Path.Combine(sharedProjectDir, "Shared.shproj")); sharedProject.AddItem("Compile", Path.GetFileName(newClassPath)); sharedProject.Save();
关键注意事项
.shproj本身不生成编译输出,所有代码的有效性依赖于引用它的宿主项目,修改后需确保宿主项目能正确编译。- 使用Roslyn操作时,共享项目的文件会作为宿主项目的一部分被加载,因此可以直接通过宿主项目的
Documents集合访问共享代码的语法树。 - 修改
.shproj后,建议刷新宿主项目的Workspace,确保Roslyn能及时识别新添加的文件。
内容的提问来源于stack exchange,提问作者ndrespulido
相关产品推荐
相关产品推荐

