VS项目引用破坏了GUID的大小写敏感性

自从升级到VS 2015以来,我的团队经历了随机古怪的事情,我肯定现在正在微软解决这个问题。 一个令人讨厌的问题是我们似乎失去了项目引用,特别是在分支之后。 我昨天开始研究我们解决方案的一个新分支,但却发现这些类型无法识别,并且名称空间使用被引用为不必要的(因为它们是针对突然变得无法识别的类型)。

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

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

旧的,破碎的参考:

 {95d34b2e-2ceb-499e-ab9e-b644b0af710d} Project.Name.Redacted  

新的固定参考:

  {95D34B2E-2CEB-499E-AB9E-B644B0AF710D} Project.Name.Redacted  

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

我应该注意,这些“损坏的”引用并没有打破构建,并且它们只在错误列表中显示为IntelliSense错误,而不是构建错误。 所以,引用并没有真正被打破,它们刚刚打破了智能感知(可以说更糟糕了?!)。

TL; DR

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

背景

我们有一个大型解决方案(60多个C#项目),并且在解决方案Rebuild中经常出现问题,因为错误的构建顺序会导致无法解析尚未构建的引用项目(但应该已经构建)。 构建依赖关系和构建顺序似乎是正确的。 MSBuild批处理生成工作正常,从Visual Studio重建时只是一个问题。

使用大括号强制所有项目GUID为大写,并使用大括号将所有项目引用GUID强制为小写,以解决问题。 这通常是Visual Studio生成这些GUID的方式,但并非总是如此。

在一个全新的测试解决方案中进行一些调查,结果certificate:

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

我能够通过用全部大写或全部小写替换引用GUID来修复我们破坏的重建 – 它是关于大写和小写混合的东西,它给出了Visual Studio的问题(可能是字典中的区分大小写的字符串键)某处?)由于Visual Studio通常会使用小写GUID添加引用,这是我选择使用的选项。

正则表达式搜索和替换

为了解决这个问题,我使用基于Notepad ++ regex的搜索并替换文件以强制.csproj文件中的所有ProjectGuids都是大括号(控制台应用程序的默认设置,并且在将任何项目引用添加到项目):

 Find what: ()\{?([0-9a-f-]+)\}?() Replace with: \1{\U\2}\E\3 Search in: *.csproj 

务必打开正则表达式搜索,然后关闭匹配大小写。 并且不要搜索所有文件,或者你可以进行你不想要的更改,例如@。#proj文件中提到的* .xproj文件。 (有关使用正则表达式更改案例的其他信息,请参阅此答案 。)

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

 Find what: ()\{?([0-9a-f-]+)\}?() Replace with: \1{\L\2}\E\3 Search in: *.csproj 

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

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

 #FixGuids get-childitem -recurse | ?{ @('.sln', '.csproj', '.vbproj') -contains $_.Extension } | %{ [regex]::Replace((gc $_.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 } 

这很简单。 如果你依赖项目中的guid而不是引用,你可能想把它变成更聪明的东西。

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

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

也许有人觉得这很有用。