如何阻止 MSBuild 将反斜杠替换为正斜杠?

How do I stop MSBuild from replacing backslashes with forward slashes?

MSBuild 通常将构建文件中的反斜杠(通常在路径中找到)替换为正斜杠,这在处理跨平台项目时很有帮助。但我有一个任务,我不想让 MSBuild 触及我的反斜杠:我们的构建中有一个自定义任务,它采用正则表达式和替换任务,并更新文件。 (我用它来更新 AssemblyInfo.cs 文件中的版本号,从 git describe 获取版本号。有一个 TeamCity 构建功能可以工作,只要我能控制它何时运行,但那是不同的故事——只要说在我的 MSBuild 文件中执行此操作看起来是目前最好的方法就够了。

我的问题是 MSBuild 通过在我传递给自定义任务的属性中将反斜杠替换为正斜杠来“帮助”我,这对我的正则表达式造成了严重破坏。我写了什么:

<FileUpdate File="$(RootDir)/GlobalAssemblyInfo.cs"
            Regex='AssemblyFileVersion\("[^"]+"\)'
            ReplacementText='AssemblyFileVersion("$(VersionNumber)")' />

以及我在构建日志中得到的内容:

error : Did not manage to replace 'AssemblyFileVersion/("[^"]+"/)' with 
        'AssemblyFileVersion/("1.1.0.92"/)'

注意到我的正则表达式中的反斜杠是如何变成正斜杠的了吗?是的,这与我的 AssemblyInfo.cs 文件中的任何内容都不匹配。

我已经能够通过在我的正则表达式中完全避免使用反斜杠来解决这个问题,就像这样:

<FileUpdate File="$(RootDir)/GlobalAssemblyInfo.cs"
            Regex='AssemblyFileVersion[(]"[^"]+"[)]'
            ReplacementText='AssemblyFileVersion("$(VersionNumber)")' />

但这并不适用于所有情况。迟早我会需要一个带有 \ 的正则表达式,或者其他一些反斜杠表达式,然后我就会沉没。在那之前,我真的很想弄清楚如何告诉 MSBuild“停止帮助我!我说的是反斜杠,我的意思是反斜杠,而不是正斜杠,在这个 ONE 属性中。你可以用其他属性来“帮助”我你喜欢,但别管这个!”有什么想法吗?

您可以创建自己的替换文本任务,并通过简单地将 / 更改为 \ 或使用其他更独特的标记来控制错误替换的字符。

<UsingTask TaskName="ReplaceFileText" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
    <InputFilename ParameterType="System.String" Required="true" />
    <MatchExpression ParameterType="System.String" Required="true" />
    <ReplacementText ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
    <Reference Include="System.Core" />
    <Using Namespace="System" />
    <Using Namespace="System.IO" />
    <Using Namespace="System.Text.RegularExpressions" />
    <Code Type="Fragment" Language="cs">
        <![CDATA[
            File.WriteAllText(
                InputFilename,
                Regex.Replace(File.ReadAllText(InputFilename), MatchExpression.Replace('/', '\'), ReplacementText)
            );
          ]]>
    </Code>
</Task>