剪裁选项

以下 MSBuild 属性和项会影响剪裁的独立部署行为。 一些选项提及 ILLink,这是实现剪裁的基础工具的名称。 有关基础工具的详细信息,请参阅剪裁器文档

.NET Core 3.0 中引入了 PublishTrimmed 剪裁功能。 其他选项仅在 .NET 5 及更高版本中可用。

启用剪裁

  • <PublishTrimmed>true</PublishTrimmed>

    在发布期间启用剪裁。 这还会关闭不兼容剪裁的功能,并在生成期间启用剪裁分析

注意

如果将剪裁指定为从命令行启用,调试体验将有所不同,并且可能会在最终产品中遇到其他 bug。

将此设置放入项目文件中,以确保不只是在 dotnet publish 期间,在 dotnet build 期间也会应用该设置。

此设置启用剪裁,默认情况下会剪裁所有程序集。 在 .NET 6 中,默认情况下,只有选择通过 [AssemblyMetadata("IsTrimmable", "True")] 剪裁的程序集才会进行剪裁。 可以使用 <TrimMode>partial</TrimMode> 返回到之前的行为。

此设置剪裁已配置用于剪裁的所有程序集。 在 .NET 6 的 Microsoft.NET.Sdk 中,将剪裁具有 [AssemblyMetadata("IsTrimmable", "True")] 的所有程序集,.NET 运行时程序集就是这种情况。 在 .NET 5 中,netcoreapp 运行时包中的程序集配置为通过 <IsTrimmable> MSBuild 元数据进行剪裁。 其他 SDK 可定义不同的默认值。

此设置还启用兼容剪裁的 Roslyn 分析器,并禁用不兼容剪裁的功能

剪裁粒度

使用 TrimMode 属性将剪裁粒度设置为 partialfull。 控制台应用(从 .NET 8 开始,Web SDK 应用)的默认设置为 full

<TrimMode>full</TrimMode>

若要仅剪裁已选择剪裁的程序集,请将该属性设置为 partial

<TrimMode>partial</TrimMode>

如果将剪裁模式更改为 partial, 则可以使用 <TrimmableAssembly> 选择单个程序集进行剪裁。

<ItemGroup>
  <TrimmableAssembly Include="MyAssembly" />
</ItemGroup>

这相当于在生成程序集时设置 [AssemblyMetadata("IsTrimmable", "True")]

以下粒度设置控制如何丢弃未充分利用的 IL。 可将其设置为影响所有剪裁器输入程序集的属性,或者设置为可替代该属性设置的单个程序集上的元数据。

  • <TrimMode>link</TrimMode>

    启用成员级剪裁,这会从类型中删除未使用的成员。 这是 .NET 6+ 中的默认设置。

  • <TrimMode>copyused</TrimMode>

    启用程序集级剪裁;如果使用程序集的任何部分(以静态理解的方式),则将保留整个程序集。

具有 <IsTrimmable>true</IsTrimmable> 元数据但没有显式 TrimMode 的程序集将使用全局 TrimModeMicrosoft.NET.Sdk 的默认 TrimMode 在 .NET 6+ 中为 link,在先前版本中为 copyused

剪裁其他程序集

在 .NET 6+ 中,PublishTrimmed 使用以下程序集级别的属性剪裁程序集:

[AssemblyMetadata("IsTrimmable", "True")]

框架库具有此属性。 在 .NET 6+ 中,还可选择按名称指定程序集(不带 .dll 扩展名),在不使用此属性的情况下对库进行剪裁。

单个程序集的剪裁设置

发布剪裁后的应用时,SDK 将计算名为 ManagedAssemblyToLinkItemGroup,这表示要进行剪裁处理的文件集。 ManagedAssemblyToLink 可能具有控制每个程序集剪裁行为的元数据。 若要设置此元数据,请在内置的 PrepareForILLink 目标运行之前创建一个目标。 下面的示例演示如何启用 MyAssembly 的剪裁。

<Target Name="ConfigureTrimming"
        BeforeTargets="PrepareForILLink">
  <ItemGroup>
    <ManagedAssemblyToLink Condition="'%(Filename)' == 'MyAssembly'">
      <IsTrimmable>true</IsTrimmable>
    </ManagedAssemblyToLink>
  </ItemGroup>
</Target>

还可为具有 [AssemblyMetadata("IsTrimmable", "True"]) 的程序集设置 <IsTrimmable>false</IsTrimmable>,用它来替代库创建者指定的剪裁行为。

请勿在 ManagedAssemblyToLink 中添加或移除项,因为 SDK 会在发布过程中计算此集,并期望它没有发生更改。 支持的元数据为:

  • <IsTrimmable>true</IsTrimmable>

    控制是否剪裁给定的程序集。

  • <TrimMode>copyused</TrimMode><TrimMode>link</TrimMode>

    控制此程序集的剪裁粒度。 这优先于全局 TrimMode。 在程序集上设置 TrimMode 意味着 <IsTrimmable>true</IsTrimmable>

  • <TrimmerSingleWarn>True</TrimmerSingleWarn><TrimmerSingleWarn>False</TrimmerSingleWarn>

    控制是否显示此程序集的单个警告

根程序集

如果某个程序集未经剪裁,则将其视为“根”,这意味着将保留它及其所有静态理解的依赖项。 其他程序集的名称可能是根(无 .dll 扩展名):

<ItemGroup>
  <TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>

根描述符

指定分析的根的另一种方法是使用剪裁器描述符格式的 XML 文件。 这使你可以查找特定的成员而非整个程序集。

<ItemGroup>
  <TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>

例如,MyRoots.xml 可能会查找由应用程序动态访问的特定方法:

<linker>
  <assembly fullname="MyAssembly">
    <type fullname="MyAssembly.MyClass">
      <method name="DynamicallyAccessedMethod" />
    </type>
  </assembly>
</linker>

分析警告

  • <SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>

    启用剪裁分析警告。

剪裁将删除不可静态访问的 IL。 使用反射或其他模式来创建动态依赖项的应用可能会因剪裁而中断。 要警告此类模式,请将 <SuppressTrimAnalysisWarnings> 设置为 false。 这将包括有关整个应用的警告,其中包括你自己的代码、库代码以及框架代码。

Roslyn 分析器

在 .NET 6 及更高版本中设置 PublishTrimmed 还将启用 Roslyn 分析器,该分析器仅显示有限的一组分析警告。 还可独立于 PublishTrimmed 启用或禁用该分析器。

  • <EnableTrimAnalyzer>true</EnableTrimAnalyzer>

    为一部分剪裁分析警告启用 Roslyn 分析器。

禁止显示警告

可以使用工具链遵循的常用 MSBuild 属性来取消单个警告代码,包括 NoWarnWarningsAsErrorsWarningsNotAsErrorsTreatWarningsAsErrors。 还有另一个选项,可单独控制 ILLink 警告即错误的行为:

  • <ILLinkTreatWarningsAsErrors>false</ILLinkTreatWarningsAsErrors>

    请勿将 ILLink 警告视为错误。 在全局将编译器警告视为错误时,这对于避免将剪裁分析警告转换为错误可能很有用。

显示详细警告

在 .NET 6 及更高版本中,对于来自 PackageReference 的每个程序集,剪裁分析最多为其生成一个警告,以指示程序集的内部机制与剪裁功能不兼容。 你还可显示所有程序集的各个警告:

  • <TrimmerSingleWarn>false</TrimmerSingleWarn>

    显示所有详细警告,而不是将其折叠为每个程序集的单个警告。

删除符号

通常会对符号进行剪裁,以匹配剪裁的程序集。 还可以删除所有符号:

  • <TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>

    删除剪裁后的应用程序中的符号,包括嵌入的 PDB 和单独的 PDB 文件。 这同时适用于应用程序代码以及符号附带的任何依赖项。

SDK 还可使用属性 DebuggerSupport 来禁用调试器支持。 禁用调试器支持时,剪裁将自动删除符号(TrimmerRemoveSymbols 将默认为 true)。

剪裁框架库功能

框架库的一些功能区域随附有剪裁器指令,这些剪裁器指令可以删除已禁用功能的代码。

  • <AutoreleasePoolSupport>false</AutoreleasePoolSupport>(默认值)

    删除在支持的平台上创建自动发布池的代码。 请参阅用于托管线程的 AutoreleasePool。 这是 .NET SDK 的默认值。

  • <DebuggerSupport>false</DebuggerSupport>

    删除代码可提供更佳的调试体验。 此设置还会删除符号

  • <EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>

    删除 BinaryFormatter 序列化支持。 有关详细信息,请参阅 BinaryFormatter 序列化方法已过时

  • <EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>

    删除不安全的 UTF-7 编码代码。 有关详细信息,请参阅 UTF-7 代码路径已过时

  • <EventSourceSupport>false</EventSourceSupport>

    删除与 EventSource 相关的代码或逻辑。

  • <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>

    删除与 System.Net.Http 的诊断支持相关的代码。

  • <InvariantGlobalization>true</InvariantGlobalization>

    删除全球化特定的代码和数据。 有关详细信息,请参阅固定模式

  • <MetadataUpdaterSupport>false</MetadataUpdaterSupport>

    删除与热重载相关的元数据更新特定逻辑。

  • <StackTraceSupport>false</StackTraceSupport> (.NET 8+)

    删除对运行时生成堆栈跟踪(例如,Environment.StackTraceException.ToString)的支持。 将从堆栈跟踪字符串中删除的信息量可能取决于其他部署选项。 此选项不会影响调试器生成的堆栈跟踪。

  • <UseNativeHttpHandler>true</UseNativeHttpHandler>

    将 HttpMessageHandler 的默认平台实现用于 Android/iOS,并删除托管实现。

  • <UseSystemResourceKeys>true</UseSystemResourceKeys>

    删除 System.* 程序集的异常消息。 当 System.* 程序集中引发异常时,该消息将是简化的资源 ID,而不是完整的消息。

这些属性将导致剪裁相关代码,同时还将通过 runtimeconfig 文件禁用功能。 有关这些属性(包括相应的 runtimeconfig 选项)的详细信息,请参阅功能切换。 某些 SDK 可能具有这些属性的默认值。

剪裁时禁用的框架功能

以下功能不兼容剪裁,因为它们需要不以静态方式引用的代码。 这些设置在剪裁应用中默认处于禁用状态。

警告

启用这些功能的风险由你自担。 这些功能可能会中断经过裁剪的应用,且不会执行任何操作来保留动态引用的代码。

  • <BuiltInComInteropSupport>

    内置的 COM 支持已禁用。

  • <CustomResourceTypesSupport>

    不支持使用自定义资源类型。 将裁剪向自定义资源类型应用反射的 ResourceManager 代码路径。

  • <EnableCppCLIHostActivation>

    C++/CLI 主机激活已禁用。

  • <EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization>

    禁止 DesigntimeLicenseContextSerializer 使用 BinaryFormatter 序列化。

  • <StartupHookSupport>

    不支持使用 DOTNET_STARTUP_HOOKS 运行 Main 之前的代码。 有关详细信息,请参阅主机启动挂钩