1

我曾尝试阅读 Microsoft 文档以及 Nuget 和 Dotnet,但无法理解相应的行为。

在与我一起处理 C# 项目时,.csproj我遇到了以下情况,这是我想要实现的示例:

例如,我正在使用以下.csproj文件:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <Authors>Confluent Inc.;Andreas Heider</Authors>
    <Description>Confluent's .NET Client for Apache Kafka</Description>
    <Copyright>Copyright 2016-2020 Confluent Inc., Andreas Heider</Copyright>
    <PackageProjectUrl>https://github.com/confluentinc/confluent-kafka-dotnet/</PackageProjectUrl>
    <PackageLicenseUrl>https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/LICENSE</PackageLicenseUrl>
    <PackageIconUrl>https://raw.githubusercontent.com/confluentinc/confluent-kafka-dotnet/master/confluent_logo.png</PackageIconUrl>
    <PackageReleaseNotes>https://github.com/confluentinc/confluent-kafka-dotnet/releases</PackageReleaseNotes>
    <PackageTags>Kafka;Confluent;librdkafka</PackageTags>
    <PackageId>Confluent.Kafka</PackageId>
    <Title>Confluent.Kafka</Title>
    <AssemblyName>Confluent.Kafka</AssemblyName>
    <VersionPrefix>1.4.3</VersionPrefix>
    <TargetFrameworks>net45;net46;netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <SignAssembly>true</SignAssembly>
    <AssemblyOriginatorKeyFile>Confluent.Kafka.snk</AssemblyOriginatorKeyFile>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="librdkafka.redist" Version="1.4.2">
        <PrivateAssets Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">None</PrivateAssets>
    </PackageReference>
    <PackageReference Include="System.Memory" Version="4.5.0" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="PeterO.Cbor" Version="3.5.0" />
  </ItemGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
    <PackageReference Include="System.Console" Version="4.3.0" />
    <PackageReference Include="System.Linq" Version="4.3.0" />
    <PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
    <PackageReference Include="System.Runtime.Extensions" Version="4.3.0" />
    <PackageReference Include="System.Threading" Version="4.3.0" />
  </ItemGroup>

</Project>

正如您在最后看到ItemGroup的那样Condition=" '$(TargetFramework)' == 'netstandard1.3',我想要弄清楚的是 dotnet 是从哪里得到这个论点$(TargetFramework)的。

顺便说一句,它似乎是变量表示法$(SomeVariable)(不仅仅是TargetFramework),我很高兴能理解这些变量是从哪里以及如何被提取出来的。

有什么线索吗?

谢谢!

4

2 回答 2

2

由于已经有关于某些机制的非常详细的答案,这里有一些有用的信息可以帮助详细了解行为:

  1. “SDK=...”部分在项目的顶部和底部导入东西。

它实际上是<Import>项目内容顶端和底端语句的语法糖。这意味着 SDK 的逻辑(及其更深层次的导入)既可以设置您可以在项目中使用的默认值(Sdk.props顶部的自动导入),也可以处理您在项目中设置的值(Sdk.targets最底部的自动导入)。

  1. <PropertyGroup>元素在元素之前处理<ItemGroup>

MSBuild 以非常特定的顺序评估静态内容(即不在 a 内<Target>):属性组和导入,然后是项定义组,然后是项组。

这意味着您可以$(FooBar)在最顶部使用 an <ItemGroup>,即使在最底部<PropertyGroup>定义i 也是如此。<FooBar>

SDK 本身使用此行为 - 您的$(TargetFramework)(单数!,如果设置。稍后会详细介绍)在导入的 SDK 目标中的某些属性组中使用以设置TargetFrameworkIdentifierTargetFrameworkVersion并且TargetFrameworkMoniker- 这是代码

<PropertyGroup>s 的处理完成时,这意味着在传递<ItemGroup>元素时,您可以使用$(TargetFrameworkIdentifier).

类似的机制用于 sdk 在您的项目内容之前具有的一些项目组,这些项目组可以由项目中设置的属性(DefaultItemExcludesEnableDefaultCompileItems)控制。

  1. TargetFrameworks(复数)项目实际上构建了多次。

如果一个项目TargetFramework只有一个(复数)属性,它会导致将为其设置属性TargetFrameworks的多个子构建。TargetFramework这意味着对“外部”构建的所有内容都进行一次评估,然后针对“内部构建”对每个目标框架进行一次评估。这是代码

于 2020-07-17T09:27:28.947 回答
1

$(SomeVariable)是解析MSBuild 属性的语法。这些是键值对,可以由环境变量、MSBuild 的参数、 MSBuild 文件中<PropertyGroup>元素以及使用任务CreatePropertyMSBuild 目标定义。

TargetFramework是一种特殊的属性。如果项目只为一个目标框架构建,则在项目文件中明确设置该属性,例如:

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

在您的情况下,您的项目可以为多个框架构建,如TargetFrameworks属性中指定的(注意复数),例如:

<PropertyGroup>
  <TargetFrameworks>netcoreapp2.1;net462</TargetFrameworks>
</PropertyGroup>

当您使用 eg 构建此项目时dotnet,它实际上会多次构建项目,每个目标框架一次,本质上是TargetFramework在调用 MSBuild 时通过参数设置属性。

如果您想稍微了解一下背后的魔力,这里有两种方法可以获取有关 MSBuild 正在做什么的详细信息:

  1. 使用-pp参数让 MSBuild 将所有神奇的 .NET Core-ish 内容以及所有导入的项目文件解析为单个项目文件以供您检查。这实际上不会运行构建。

  2. 使用参数运行构建,但以二进制格式记录 MSBuild 所做的一切-bl然后,您可以使用此 GUI.binlog查看文件。

MSBuild 的其他资源:

于 2020-06-29T15:34:33.567 回答