Roslyn 和 ProjectId - 不是唯一的(实现 VSIX)
Roslyn and ProjectId - not unique (implementing VSIX)
我正在创建一些 VSIX。
现在,一开始,我使用 Roslyn 进行了一些代码分析,并从解决方案中获取了所有项目:
async Task AnalyzeCode()
{
foreach (var project in workspace.CurrentSolution.Projects)
await AnalyzeProject(project);
}
async Task AnalyzeProject(Project project)
{
Models.ProjectInfo pi = new Models.ProjectInfo();
pi.FileName = project.FilePath;
pi.Name = project.Name;
pi.Id = project.Id;
projectsInSolution.Add(pi.Name, pi);
foreach(var doc in project.Documents)
await AnalyzeDocument(pi, doc);
}
等等。如您所见,我正在从 roslyn 的项目 class 中获取 ProjectId。
此 ProjectId class 具有我稍后保存在设置中的 GUID 类型的字段 ID。
现在,当用户在解决方案资源管理器中右键单击项目节点时,我必须检查该选定项目的 ID 是否是保存在设置中的 ID。所以我使用 dte:
获取项目 ID
UIHierarchy solutionExplorer = dte.ToolWindows.SolutionExplorer;
object[] selectedItems = solutionExplorer.SelectedItems as object[];
Guid projectGuid;
if (selectedItems.Length > 0)
{
IVsHierarchy hierarchy;
Project project = (selectedItems[0] as UIHierarchyItem).Object as Project;
solution.GetProjectOfUniqueName(project.FullName, out hierarchy);
if(hierarchy != null)
hierarchy.GetGuidProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ProjectIDGuid, out projectGuid);
}
但问题是从 IVsHierarchy 读取的 projectGuid 与使用 Roslyn 读取的不同。此外,Roslyn 读取的 ProjectId.Id 在每次应用程序启动时都是不同的。当然,从 IVsHierarchy 读取的项目 guid 总是相同的,所以它必须是真正有效的项目 guid。
所以问题是 - 如何使用 Roslyn 读取真正有效的项目 guid?
ProjectId 中的 GUID 是我们每次加载项目时生成的。这也有点古怪,因为在一个针对多个框架的项目中,每个框架都有一个单独的 Id 和 GUID,即使根据 [=19 的其他部分的定义,它是一个单一的 'project' =].
如果将 Workspace 转换为 VisualStudioWorkspace,则可以使用更多方法。它看起来像我们的 convenient method to just fetch the GUID directly is internal(糟糕!),但您可以调用 VisualStudioWorkspace.GetHierarchy,以这种方式为其提供 Roslyn ProjectId,然后像在第二个代码段中那样调用 GetGuidProperty。
标准警告也适用于无法在后台线程上可靠地调用 GetGuidProperty 而不冒死锁的风险,因此如果您不熟悉线程指南,请小心。我承认从你的问题中不能完全清楚项目 GUID 是否是首先要使用的正确的东西......
我正在创建一些 VSIX。 现在,一开始,我使用 Roslyn 进行了一些代码分析,并从解决方案中获取了所有项目:
async Task AnalyzeCode()
{
foreach (var project in workspace.CurrentSolution.Projects)
await AnalyzeProject(project);
}
async Task AnalyzeProject(Project project)
{
Models.ProjectInfo pi = new Models.ProjectInfo();
pi.FileName = project.FilePath;
pi.Name = project.Name;
pi.Id = project.Id;
projectsInSolution.Add(pi.Name, pi);
foreach(var doc in project.Documents)
await AnalyzeDocument(pi, doc);
}
等等。如您所见,我正在从 roslyn 的项目 class 中获取 ProjectId。 此 ProjectId class 具有我稍后保存在设置中的 GUID 类型的字段 ID。
现在,当用户在解决方案资源管理器中右键单击项目节点时,我必须检查该选定项目的 ID 是否是保存在设置中的 ID。所以我使用 dte:
获取项目 IDUIHierarchy solutionExplorer = dte.ToolWindows.SolutionExplorer;
object[] selectedItems = solutionExplorer.SelectedItems as object[];
Guid projectGuid;
if (selectedItems.Length > 0)
{
IVsHierarchy hierarchy;
Project project = (selectedItems[0] as UIHierarchyItem).Object as Project;
solution.GetProjectOfUniqueName(project.FullName, out hierarchy);
if(hierarchy != null)
hierarchy.GetGuidProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ProjectIDGuid, out projectGuid);
}
但问题是从 IVsHierarchy 读取的 projectGuid 与使用 Roslyn 读取的不同。此外,Roslyn 读取的 ProjectId.Id 在每次应用程序启动时都是不同的。当然,从 IVsHierarchy 读取的项目 guid 总是相同的,所以它必须是真正有效的项目 guid。
所以问题是 - 如何使用 Roslyn 读取真正有效的项目 guid?
ProjectId 中的 GUID 是我们每次加载项目时生成的。这也有点古怪,因为在一个针对多个框架的项目中,每个框架都有一个单独的 Id 和 GUID,即使根据 [=19 的其他部分的定义,它是一个单一的 'project' =].
如果将 Workspace 转换为 VisualStudioWorkspace,则可以使用更多方法。它看起来像我们的 convenient method to just fetch the GUID directly is internal(糟糕!),但您可以调用 VisualStudioWorkspace.GetHierarchy,以这种方式为其提供 Roslyn ProjectId,然后像在第二个代码段中那样调用 GetGuidProperty。
标准警告也适用于无法在后台线程上可靠地调用 GetGuidProperty 而不冒死锁的风险,因此如果您不熟悉线程指南,请小心。我承认从你的问题中不能完全清楚项目 GUID 是否是首先要使用的正确的东西......