在 .NET Core 2.x csproj 项目中可靠地生成 C# 代码?



说明

我一直无法在我的 .NET 项目中可靠地生成 C# 代码。我可以让它构建 (a) 当源文件事先存在时或 (b) 当源文件事先不存在时。我无法在两种情况下使用相同的设置。

为什么这很重要:如果我在我的开发机器上构建,我以前可能已经构建过代码,所以我需要它来重新生成存在的源代码。但是,在构建机器上构建时,这些文件不存在,因此在这种情况下,我需要它从头开始生成代码。

设置

复制它只需要一个 csproj 和一个源文件。

下面是一个引用示例GeneratedClass的简单程序:

class Program
{
public static void Main(string[] args)
{
System.Console.WriteLine(GeneratedClass.MESSAGE);
}
}

这是我能想到的最简单的csproj文件。

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Target Name="GenerateCode" BeforeTargets="CoreCompile">
<!-- Removing the source code beforehand makes no difference
<Exec Command="rm $(ProjectDir)Generated/*.cs" IgnoreExitCode="true" />
-->
<Exec Command="echo 'class GeneratedClass { public static int MESSAGE = 1; }' > Generated/GeneratedClass.cs" />
<!-- Toggling this setting will cause failures in some scenarios and success in others
<ItemGroup>
<Compile Include="Generated/*$(DefaultLanguageSourceExtension)" />
</ItemGroup> -->
</Target>
</Project>

创建一个名为"已生成"的空目录。

若要生成,请从 csproj 和 Program.cs 文件所在的目录运行dotnet build

我在Linux上运行.NET Core 2.0.3。我的 Docker 构建容器使用microsoft/dotnet:2.0-sdk映像;我可以在 Docker 内部和外部复制该问题。

症状

请注意,在上面的 csproj 文件中,有一个注释掉的<Compile Include设置。另请注意,多次运行生成将生成代码。(可以手动删除代码以复制在生成开始时不存在代码的情况。

以下是我在哪里看到错误和在哪里看不到错误的矩阵:

+----------------------+----------------------+-----------------------------------+ |编译包含=...?|代码已经存在? |             结果 | +----------------------+----------------------+-----------------------------------+ |礼物 |是 |错误!"指定多次" | |礼物 |否 |成功!                         | |注释掉 |是 |成功!                         | |注释掉 |否 |错误!"不存在" | +----------------------+----------------------+-----------------------------------+

"指定多次"错误的完整错误文本:/usr/share/dotnet/sdk/2.0.3/Roslyn/Microsoft.CSharp.Core.targets(84,5): error MSB3105: The item "Generated/GeneratedClass.cs" was specified more than once in the "Sources" parameter. Duplicate items are not supported by the "Sources" parameter. [/home/user/tmp/CodeGenExample.csproj]

"不存在"错误的完整错误文本:Program.cs(5,34): error CS0103: The name 'GeneratedClass' does not exist in the current context [/home/user/tmp/CodeGenExample.csproj]

请求帮助

我最好的猜测是我的BeforeTargets="CoreCompile"是错误的。我在那里尝试了很多不同的值(对不起,不记得是哪些),我总是遇到这样或那样的问题。这只是一个猜测。

我做错了什么?

免责声明:您的实际项目中似乎有上述内容中没有的内容,所以我不确定此解决方案是否有效。

下面是一个黑客方法,因为它的行为并不完全符合预期。
然而,它可能足以满足你的目的 - 这是由你决定的。 我说它很hacky的原因是预构建文件删除似乎确实执行了不止一次。1

我拥有的 csproj 文件是这样做的:

  1. 删除生成目录中的所有文件。 这是通过CleanGen目标完成的,并在"项目"节点中作为初始目标启动。
  2. Generated Code目标追加到输出文件,以证明它只发生一次。
  3. 启用"项组"节点以允许编译生成的文件。
  4. 回显变量$(NuGetPackageRoot)以显示它已设置。

在此处完成 csproj 文件:

<Project InitialTargets="CleanGen" Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Target Name="CleanGen">
<Exec Command="echo 'Cleaning files...'" />
<Exec Command="rm $(ProjectDir)Generated/*$(DefaultLanguageSourceExtension)" IgnoreExitCode="true" />
</Target>
<Target Name="GenerateCode" BeforeTargets="CoreCompile">
<Exec Command="echo 'Generating files... $(NuGetPackageRoot)'" />
<Exec Command="echo 'class GeneratedClass { public static int MESSAGE = 1; }' >> Generated/GeneratedClass.cs" />
<ItemGroup>
<Compile Include="Generated/*$(DefaultLanguageSourceExtension)" />
</ItemGroup>
</Target>
</Project>

这看起来确实比应该的要难......


1OP 指出,为避免多次执行rm命令,您可以向Exec添加Condition

<Exec 
Command="rm $(ProjectDir)Generated/*$(DefaultLanguageSourceExtension)"
Condition="Exists('$(ProjectDir)Generated/GeneratedClass$(DefaultLanguageSourceExtension)')" />

不幸的是,Exists不接受 glob,因此您必须指定至少一个您知道将在该文件夹中生成的特定文件。通过这种妥协,您还可以摆脱IgnoreExitCode="true"因为它应该仅在有文件要删除时才执行。

我能够通过重新包含生成的项目来使其工作:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Target Name="GenerateCode" BeforeTargets="CoreCompile">
<Exec Command="mkdir Generated" Condition="!Exists('Generated')" />
<Exec Command="echo class GeneratedClass { public static int MESSAGE = 1; } > Generated/GeneratedClass.cs" />
<ItemGroup>
<Compile Include="Generated/*$(DefaultLanguageSourceExtension)" Exclude="@(Compile)" />
</ItemGroup>
</Target>
</Project>

更新 4/16/2019

SpecFlow 3 使用一个巧妙的Exclude="@(Compile)"技巧来编译生成的文件 (https://specflow.org/2019/updating-to-specflow-3/):

<ItemGroup>
<Compile Include="Generated/*$(DefaultLanguageSourceExtension)" Exclude="@(Compile)" />
</ItemGroup>

更新 9/20/2018

请在此处查看示例 git 存储库:https://github.com/altso/SO49075282

cmd中重现的步骤:

C:Temp>dotnet --version
2.1.402
C:Temp>git clone https://github.com/altso/SO49075282.git
Cloning into 'SO49075282'...
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 5 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), done.
C:Temp>cd SO49075282
C:TempSO49075282>dotnet build
Microsoft (R) Build Engine version 15.8.166+gd4e8d81a88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restoring packages for C:TempSO49075282SO49075282.csproj...
Generating MSBuild file C:TempSO49075282objSO49075282.csproj.nuget.g.props.
Generating MSBuild file C:TempSO49075282objSO49075282.csproj.nuget.g.targets.
Restore completed in 311.61 ms for C:TempSO49075282SO49075282.csproj.
SO49075282 -> C:TempSO49075282binDebugnetcoreapp2.1SO49075282.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.95
C:TempSO49075282>dotnet build
Microsoft (R) Build Engine version 15.8.166+gd4e8d81a88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 60.66 ms for C:TempSO49075282SO49075282.csproj.
SO49075282 -> C:TempSO49075282binDebugnetcoreapp2.1SO49075282.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.17
C:TempSO49075282>

相关内容

  • 没有找到相关文章

最新更新