VS 项目引用因 GUID 区分大小写而损坏

VS Project References Broken On Case Sensitivity of GUID

自从升级到 VS 2015 后,我的团队经历了一些奇怪的事情,我相信现在 Microsoft 正在解决这些事情。一个非常烦人的问题是我们似乎丢失了项目引用,尤其是在分支之后。我昨天开始研究我们解决方案的一个新分支,结果发现类型无法识别,并且命名空间使用被认为是不必要的(因为它们是针对突然变得无法识别的类型)。

项目中的引用没有显示任何指示引用有问题的图标,但为了看看它是否有效,我删除并重新添加了一个项目引用,这导致它的类型再次被识别.

这当然更新了项目文件,所以我查看了哪些更改。无法检测到引用的项目与现在可以检测到的项目之间的唯一区别是 GUID 中的字母字符已从小写更改为大写。例如:

旧的、损坏的引用:

<ProjectReference Include="path/redacted">
    <Project>{95d34b2e-2ceb-499e-ab9e-b644b0af710d}</Project>
    <Name>Project.Name.Redacted</Name>
</ProjectReference>

新的固定参考:

<ProjectReference Include="path/redacted">
    <Project>{95D34B2E-2CEB-499E-AB9E-B644B0AF710D}</Project>
    <Name>Project.Name.Redacted</Name>
</ProjectReference>

我正在寻找发生这种情况的原因以及如何修复它而无需手动删除并重新添加所有引用(并且无需将所有项目文件 GUID 转换为大写) .

我应该注意到,这些 "broken" 引用并没有破坏构建,它们只在错误列表中显示为 IntelliSense 错误,而不是构建错误。因此,引用并没有真正损坏,它们只是损坏了 IntelliSense(可以说更糟?!)。

项目系统中似乎存在错误。这个 powershell 将遍历项目并使所有引用大写:

#FixGuids

get-childitem -recurse | ?{ @('.sln', '.csproj', '.vbproj') -contains $_.Extension } | %{
   [regex]::Replace((gc -raw $_.FullName), '[{(]?[0-9A-Fa-f]{8}[-]?([0-9A-Fa-f]{4}[-]?){3}[0-9A-Fa-f]{12}[)}]?', { return ([string]$args[0]).ToUpperInvariant() }) |
      Out-File $_.FullName -Encoding "UTF8
}

这很简单。如果您在项目中依赖 guid 来获取引用以外的内容,您可能希望将其变成更智能的内容。

TL;DR

Visual Studio 关于如何将 GUID 分配给项目 如何在项目引用中指定这些 GUID 并不完全一致。我能够通过对 ProjectGuid 元素使用带大括号的大写 GUID 和对 Project 元素使用带大括号的小写 GUID(在参考文献中)来解决问题。

背景

我们有一个大型解决方案(60 多个 C# 项目),并且解决方案重建经常出现问题,因为不正确的构建顺序会导致无法解析尚未构建(但应该已经构建)的引用项目。 Build Dependencies 和 Build Order 看起来是正确的。 MSBuild 批量构建工作正常,只是从 Visual Studio.

重建时出现问题

强制所有项目 GUID 为带大括号的大写字母和所有项目引用 GUID 为带大括号的小写字母修复了问题。这是通常 Visual Studio 如何生成这些 GUID,但并非总是如此。

在一个全新的测试解决方案中做了一些调查,结果是:

  1. 为控制台应用程序项目生成的 GUID 是带大括号的大写。
  2. 为 class 库项目生成的 GUID 最初是小写的,没有大括号。
  3. 如果新项目引用添加了一个 class 具有小写 GUID 的库项目,那么不仅会添加引用 GUID,而且项目 GUID 会通过大括号转换为大写。
  4. 如果制作了 class 库项目的副本,然后将其添加到解决方案中,则其 GUID 将替换为使用大写字母和大括号的新项目。 (但是,如果创建副本并手动删除其 GUID,Visual Studio 不会将替换 GUID 插入 .csproj 文件。)
  5. 项目引用的 GUID 通常使用小写和大括号,但不知何故我们的项目积累了一堆大写的 GUID 引用。
  6. .sln 中的 GUID 始终使用大写字母和大括号。

我能够通过将参考 GUID 替换为全部大写或全部小写来修复我们损坏的重建——这是关于大写和小写的混合导致 Visual Studio 问题(也许某处字典中区分大小写的字符串键?)因为 Visual Studio 通常添加小写 GUID 的引用,这是我选择的选项。

正则表达式搜索和替换

为了解决这个问题,我在文件中使用了基于 Notepad++ 正则表达式的搜索和替换来强制 .csproj 文件中的所有 ProjectGuids 为带大括号的大写字母(控制台应用程序的默认设置,样式 Visual Studio 将在向项目添加任何项目引用后应用):

Find what: (<ProjectGuid>)\{?([0-9a-f-]+)\}?(</ProjectGuid>)
Replace with: {\U}\E
Search in: *.csproj

一定要打开正则表达式搜索,关闭匹配大小写。并且不要搜索所有文件,否则您可能会进行不需要的更改,例如在 *.xproj 文件中,如@AspNyc 所述。 (有关使用正则表达式更改大小写的更多信息,请参阅 this answer。)

然后我将所有对项目的引用替换为使用带大括号的小写字母(Visual Studio 通常这样做):

Find what: (<Project>)\{?([0-9a-f-]+)\}?(</Project>)
Replace with: {\L}\E
Search in: *.csproj

进行这些更改后,Visual Studio 解决方案重建现在可以可靠地工作。 (至少在下一次流氓大写参考 GUID 潜入我们的项目之前。)

为了在 git 挂钩中使用答案,我必须将其转换为 sed 的正则表达式语法:

sed -r "s/(<Project>\{?)([0-9A-F-]+)(\}?<\/Project>)/\L\E/g" sample.csproj

也许有人觉得这有用。

我在将 VS2017 v15.7 更新到 v15.9 时遇到了类似的问题。

我的答案是关闭 VS,清除解决方案根目录中隐藏的 .vs 文件夹,然后重新启动 VS。

2019 年 visual studio (16.2.2) 的今天,我遇到了构建系统问题,每当我开始构建我的解决方案时,项目都会被不必要地(并重复地)重建。

(None 的常用步骤解决了构建问题,例如删除“.vs”文件夹,或删除 "bin" 和 "obj" 目录等)。

起初它似乎与 guid 的字符大小写有关,因为我能够通过编辑 guid 并保存项目来解决问题。然而,这是一个转移注意力的问题……我通过更改所有 csproj 文件的时间戳无意中解决了这个问题。更新这些时间戳后,构建系统似乎更快乐了,并且它停止了烦人的行为(不断尝试重建已经构建的项目。)

guids 的字符大小写根本不是问题。据我所知,VS 2019 可以使用大写和小写 guid。根据我的实验,它们甚至可能与源项目不匹配(例如,原始源项目可以使用大写字母,而引用项目可以使用小写字母)。

如果对任何人有帮助,下面是一个 powershell,可让您调整路径下所有 csproj 文件的写入时间。每当 msbuild 系统在 visual studio 中出现异常时,这将是我使用的另一个技巧。

$datenow = get-date

$files = Get-ChildItem -path "C:\Data\Workspaces\LumberTrack\" -recurse | where { $_.PSIsContainer -eq $false} 

foreach ($file in $files)
{
if ($file.Extension -eq ".csproj") 
{
   Set-ItemProperty $file.FullName LastWriteTime $datenow
   Write-Output $file.FullName
}    
}    
}