From f745fc9f08066c1b8e2fef4186446cd620eb2c00 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 1 Aug 2023 19:07:11 -1000
Subject: [PATCH 01/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 39 +++++++++++++++----
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 7f08bec781dbd..496e9448520b6 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -10,22 +10,45 @@ ms.date: 06/12/2023
The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md), which removes unused code from the app and its dependencies. Not all code is compatible with trimming, so .NET 6 provides trim analysis warnings to detect patterns that may break trimmed apps. To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). This article describes how to prepare libraries for trimming with the aid of these warnings, including recommendations for fixing some common cases.
-## Enable library trim warnings
+## Prerequisites
+
+### [.NET 6](#tab/net6)
+
+[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet)
+
+### [.NET 7](#tab/net7)
+
+[.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet)
+
+### [.NET 8+](#tab/net8plus)
+
+[.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet)
+
+---
-> [!TIP]
-> Ensure you're using the .NET 6 SDK or later for these steps. They will not work correctly in previous versions.
+## Enable library trim warnings
-There are two ways to find trim warnings in your library:
+There are two ways to find trim warnings in a library:
- 1. Enable project-specific trimming using the `IsTrimmable` property.
- 2. Add your library as a reference to a sample app, and trim the sample app.
+* Enable project-specific trimming using the `IsTrimmable` property.
+* Add the library as a reference to a sample app, and trim the sample app.
Consider doing both. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a sample app is more work, but will always show all warnings.
### Enable project-specific trimming
-> [!TIP]
-> To get the latest version of the analyzer with the most coverage, use the [.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet). Note this will only update the tooling used to build your app and doesn't require you to target the .NET 7 runtime.
+### [.NET 6](#tab/net6)
+
+To get the latest version of the analyzer with the most coverage, install the [.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet) or later. Installing the .NET 7 SDK or later:
+
+* Updates the tooling used to build an app or library and enable trim warnings.
+* Doesn't require targeting the .NET 7 or later runtime.
+
+### [.NET 7](#tab/net7)
+
+### [.NET 8+](#tab/net8plus)
+
+---
Set `true` in a `` tag in your library project file. This marks your assembly as "trimmable" and enable trim warnings for that project. Being "trimmable" means your library is considered compatible with trimming and should have no trim warnings when building the library. When used in a trimmed application, the assembly has its unused members trimmed in the final output.
From 2298407c74e55916fae7e7bacab1939e0cc27afa Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 09:09:15 -1000
Subject: [PATCH 02/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 496e9448520b6..8f022381ccc23 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -44,17 +44,26 @@ To get the latest version of the analyzer with the most coverage, install the [.
* Updates the tooling used to build an app or library and enable trim warnings.
* Doesn't require targeting the .NET 7 or later runtime.
+Set `true` in the project file.
+
### [.NET 7](#tab/net7)
+Set `true` in the project file.
+
### [.NET 8+](#tab/net8plus)
+Set `true` in the project file.
+
---
-Set `true` in a `` tag in your library project file. This marks your assembly as "trimmable" and enable trim warnings for that project. Being "trimmable" means your library is considered compatible with trimming and should have no trim warnings when building the library. When used in a trimmed application, the assembly has its unused members trimmed in the final output.
+Setting `true` marks the assembly as "trimmable" and enables trim warnings. "trimmable" means the project:
+
+* Is considered compatible with trimming.
+* Shouldn't trim warnings when building. When used in a trimmed app, the assembly has its unused members trimmed in the final output.
-The `IsTrimmable` property defaults to `true` when configuring a library as AOT-compatible (`true`). For more information, see [AOT-compatibility analyzers](../native-aot/index.md#aot-compatibility-analyzers).
+The `IsTrimmable` property defaults to `true` when configuring a project as AOT-compatible with `true`. For more information, see [AOT-compatibility analyzers](../native-aot/index.md#aot-compatibility-analyzers).
-If you want to see trim warnings, but don't want to mark your library as trim-compatible, you can add `true` instead.
+To generate trim warnings without marking the project as trim-compatible, use `true` rather than `true`.
### Show all warnings with sample application
From 6cd4bc943fa8dd65e3665c3fac6b29c5c7fbc7d4 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 11:31:32 -1000
Subject: [PATCH 03/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 8f022381ccc23..16760bd42a8bf 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -16,24 +16,26 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet)
-### [.NET 7](#tab/net7)
+### [.NET 7](#tab/net7plus)
[.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet)
+
### [.NET 8+](#tab/net8plus)
[.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet)
+-->
---
## Enable library trim warnings
-There are two ways to find trim warnings in a library:
+Trim warnings in a library can be found with either of the following methods:
-* Enable project-specific trimming using the `IsTrimmable` property.
-* Add the library as a reference to a sample app, and trim the sample app.
+* Enabling project-specific trimming using the `IsTrimmable` property.
+* Added the library as a reference to a sample app, and trim the sample app.
-Consider doing both. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a sample app is more work, but will always show all warnings.
+We recommend using both approaches. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a sample app is more work, but shows all warnings.
### Enable project-specific trimming
From 2a6ab046d6f75f40052e3d4471e3cdc8ba109ce4 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 11:53:10 -1000
Subject: [PATCH 04/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 24 +++----------------
1 file changed, 3 insertions(+), 21 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 16760bd42a8bf..05b649e55ba3c 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -12,21 +12,7 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
## Prerequisites
-### [.NET 6](#tab/net6)
-
-[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet)
-
-### [.NET 7](#tab/net7plus)
-
-[.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet)
-
-
-### [.NET 8+](#tab/net8plus)
-
-[.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet)
--->
-
----
+[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet) or later.
## Enable library trim warnings
@@ -41,18 +27,14 @@ We recommend using both approaches. Project-specific trimming is convenient and
### [.NET 6](#tab/net6)
-To get the latest version of the analyzer with the most coverage, install the [.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet) or later. Installing the .NET 7 SDK or later:
+To get the latest version of the analyzer with the most coverage, install the [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet) or later. Installing the .NET 8 SDK or later:
* Updates the tooling used to build an app or library and enable trim warnings.
* Doesn't require targeting the .NET 7 or later runtime.
Set `true` in the project file.
-### [.NET 7](#tab/net7)
-
-Set `true` in the project file.
-
-### [.NET 8+](#tab/net8plus)
+### [.NET 7+](#tab/net7plus)
Set `true` in the project file.
From fceae61920dec9f716e71ab227aca1c78ce3c3d1 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 11:59:35 -1000
Subject: [PATCH 05/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 6 ++++++
.../trimming/snippets/MyLibrary/Class1.cs | 7 +++++++
.../trimming/snippets/MyLibrary/MyLibrary.csproj | 15 +++++++++++++++
3 files changed, 28 insertions(+)
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 05b649e55ba3c..7aaf4d1f58387 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -40,6 +40,12 @@ Set `true` in the project file.
---
+:::code language="xml" source="~/docs/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
+
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
+
+:::code language="xml" source="~/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
+
Setting `true` marks the assembly as "trimmable" and enables trim warnings. "trimmable" means the project:
* Is considered compatible with trimming.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
new file mode 100644
index 0000000000000..d6fadd62c72df
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -0,0 +1,7 @@
+namespace MyLibrary
+{
+ public class Class1
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
new file mode 100644
index 0000000000000..70799093352b2
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+ //
+
+ true
+
+ //
+
+
From 74e8cc3a10e9bf5ec91f02a10666d8c5c81c8a55 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 12:04:28 -1000
Subject: [PATCH 06/57] Update trimming doc
---
.../deploying/trimming/snippets/MyLibrary/MyLibrary.csproj | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
index 70799093352b2..ef1c47ad7ad3e 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
@@ -6,10 +6,10 @@
enable
- //
+
true
- //
+
From 245066eb0a8f0db61260ad2167eaa2a1f2107ce2 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 12:32:58 -1000
Subject: [PATCH 07/57] Update trimming doc
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 7aaf4d1f58387..a0130a0427c01 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -40,16 +40,20 @@ Set `true` in the project file.
---
+source="~/docs/docs/
+
:::code language="xml" source="~/docs/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
+source="~/docs/core/
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
+source="~/core/deployi
:::code language="xml" source="~/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
Setting `true` marks the assembly as "trimmable" and enables trim warnings. "trimmable" means the project:
* Is considered compatible with trimming.
-* Shouldn't trim warnings when building. When used in a trimmed app, the assembly has its unused members trimmed in the final output.
+* Shouldn't generate trim warnings when building. When used in a trimmed app, the assembly has its unused members trimmed in the final output.
The `IsTrimmable` property defaults to `true` when configuring a project as AOT-compatible with `true`. For more information, see [AOT-compatibility analyzers](../native-aot/index.md#aot-compatibility-analyzers).
From 6de398e91e8980c4890753e8aa15e138d3bc8e99 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 13:17:38 -1000
Subject: [PATCH 08/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index a0130a0427c01..066ba3b899338 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -40,20 +40,12 @@ Set `true` in the project file.
---
-source="~/docs/docs/
-
-:::code language="xml" source="~/docs/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
-
-source="~/docs/core/
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
-source="~/core/deployi
-:::code language="xml" source="~/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
-
Setting `true` marks the assembly as "trimmable" and enables trim warnings. "trimmable" means the project:
* Is considered compatible with trimming.
-* Shouldn't generate trim warnings when building. When used in a trimmed app, the assembly has its unused members trimmed in the final output.
+* Shouldn't generate trim related warnings when building. When used in a trimmed app, the assembly has its unused members trimmed in the final output.
The `IsTrimmable` property defaults to `true` when configuring a project as AOT-compatible with `true`. For more information, see [AOT-compatibility analyzers](../native-aot/index.md#aot-compatibility-analyzers).
From 3a4c3c2e713efd648c08d091dbb82331c508e5fd Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 14:44:20 -1000
Subject: [PATCH 09/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 125 +++++++-----------
.../trimming/snippets/MyLibrary/Class1.cs | 42 +++++-
.../snippets/MyLibrary/MyLibrary.csproj | 19 +--
.../snippets/MyLibrary/MyLibrary.csproj.txt | 15 +++
.../MyTestLib6app/MyTestLib6app.csproj | 18 +++
.../snippets/MyTestLib6app/Program.cs | 2 +
6 files changed, 129 insertions(+), 92 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt
create mode 100644 docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj
create mode 100644 docs/core/deploying/trimming/snippets/MyTestLib6app/Program.cs
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 066ba3b899338..1554254658653 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -40,7 +40,7 @@ Set `true` in the project file.
---
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj" id="snippet" highlight="2":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt" id="snippet" highlight="2":::
Setting `true` marks the assembly as "trimmable" and enables trim warnings. "trimmable" means the project:
@@ -51,27 +51,41 @@ The `IsTrimmable` property defaults to `true` when configuring a project as AOT-
To generate trim warnings without marking the project as trim-compatible, use `true` rather than `true`.
-### Show all warnings with sample application
+### Show all warnings with sample app
-To show all analysis warnings for your library, including warnings about dependencies, you need the trimmer to analyze the implementation of your library and the implementations of dependencies your library uses. When building and publishing a library, the implementations of the dependencies aren't available, and the available reference assemblies don't have enough information for the trimmer to determine if they're compatible with trimming. Because of this, you need to create and publish a self-contained sample application, which produces an executable that includes your library and the dependencies it relies on. This executable includes all the information the trimmer requires to warn you about all trim incompatibilities in your library code, and the code that your library references from its dependencies.
+To show all analysis warnings for a library, the trimmer must analyze the implementation:
-> [!NOTE]
-> If your library has significantly different behavior or uses different APIs depending on the target framework of the consumer (for example, using `#if NET7_0`) which might impact trimming, you will need to create a new sample app for each of the target frameworks you want to support trimming for.
+* Of the library.
+* All dependencies the library uses.
-To create your sample app, first create a separate console application project with `dotnet new console` and modify the project file to look like the following. No changes to the source code are necessary. You need to do the following in your project file:
+When building and publishing a library:
-- Set the PublishTrimmed property to `true` with `true` in a `` tag.
-- Add a reference to your library project with `` inside of an `` tag.
-- Specify your library as a trimmer root assembly with `` in an `` tag.
- - This ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root," which means the trimmer analyzes the assembly as if everything were used, and traverses all possible code paths that originate from that assembly. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it.
-- If your app targets .NET 6, set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
-- If your app targets .NET 7, [the new default behavior](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md) is what you want, but you can enforce the behavior by adding `full` in a `` tag.
- - This ensures that the trimmer only analyzes the parts of the library's dependencies that are used. It tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library.
+* The implementations of the dependencies aren't available.
+* The available reference assemblies don't have enough information for the trimmer to determine if they're compatible with trimming.
+
+Because the dependency limitations, a self-contained sample app which uses the libary and it's dependencies must be created. The sample app executable includes all the information the trimmer requires to issue warning on trim incompatibilities in:
+
+* The library code.
+* The code that the library references from its dependencies.
+
+***Note:*** If the library has significantly different behavior depending on the target framework, create a sample app for each of the target frameworks. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
+
+To create the sample app, create a separate console application project with `dotnet new console` and modify the project file to look like the following. You need to do the following in your project file:
+
+* Add `true`.
+* Add a reference to the library project with ``.
+* Specify the library as a trimmer root assembly with ``.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root,". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
+* If your app targets .NET 6, set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
+
+ *
##### .csproj file
### [.NET 6](#tab/net6)
+Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
+
```xml
@@ -93,96 +107,47 @@ To create your sample app, first create a separate console application project w
```
-### [.NET 7](#tab/net7)
-
-```xml
-
-
-
- Exe
- net7.0
- true
-
-
-
-
-
-
-
-
-
-```
+### [.NET 7+](#tab/net7plus)
-### [.NET 8+](#tab/net8plus)
+Use the [.NET 7 and higher default behavior](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md), which can enforce the behavior by adding `full`.
-```xml
-
+`full`:
-
- Exe
- net8.0
- true
-
+* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
+* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option, warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "Tue")]`, including parts that are unused by the library.
-
-
-
-
-
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt":::
-
-```
+Note: In the preceding project file, when using .NET 8, replace `net7.0` with `net8.0`.
---
-Once your project file is updated, run `dotnet publish` with the [runtime identifier (RID)](../../rid-catalog.md) you want to target.
+Once the project file is updated, run `dotnet publish` with the target [runtime identifier (RID)](../../rid-catalog.md).
```dotnetcli
dotnet publish -c Release -r
```
-You can also follow the same pattern for multiple libraries. To see trim analysis warnings for more than one library at a time, add them all to the same project as `ProjectReference` and `TrimmerRootAssembly` items. This warns about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only.
+Follow the same pattern for multiple libraries. To see trim analysis warnings for more than one library at a time, add them all to the same project as `ProjectReference` and `TrimmerRootAssembly` items. Adding all the libraries to the same project with `ProjectReference` and `TrimmerRootAssembly` items warns about dependencies if ***any*** of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only.
-> [!NOTE]
-> The analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`.
+***Note:*** The analysis results depend on the implementation details of the dependencies. Updating to a new version of a dependency may introduce analysis warnings:
-## Resolve trim warnings
+* If the new version added non-understood reflection patterns.
+* Even if there were no API changes.
-The above steps produce warnings about code that may cause problems when used in a trimmed app. Here are a few examples of the most common kinds of warnings you may encounter, with recommendations for fixing them.
+Introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`.
-### RequiresUnreferencedCode
+## Resolve trim warnings
-```csharp
-using System.Diagnostics.CodeAnalysis;
+The preceding steps produce warnings about code that may cause problems when used in a trimmed app. The following examples show the most common warnings with recommendations for fixing them.
-public class MyLibrary
-{
- public static void Method()
- {
- // warning IL2026 : MyLibrary.Method: Using method 'MyLibrary.DynamicBehavior'
- // which has 'RequiresUnreferencedCodeAttribute' can break functionality
- // when trimming application code.
- DynamicBehavior();
- }
+### RequiresUnreferencedCode
- [RequiresUnreferencedCode(
- "DynamicBehavior is incompatible with trimming.")]
- static void DynamicBehavior()
- {
- }
-}
-```
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="5-11":::
This means the library calls a method that has explicitly been annotated as incompatible with trimming, using . To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Method` get a warning instead:
-```csharp
-// Warn for calls to Method, but not for Method's call to DynamicBehavior.
-[RequiresUnreferencedCode("Calls DynamicBehavior.")]
-public static void Method()
-{
- DynamicBehavior(); // OK. Doesn't warn now.
-}
-```
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode" highlight="5":::
Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you're done. Apps that call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index d6fadd62c72df..411eba0680e05 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,7 +1,43 @@
-namespace MyLibrary
+#define RequiresUnreferencedCode // FIRST RequiresUnreferencedCode
+#if NEVER
+#elif FIRST
+//
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
+{
+ public static void Method()
+ {
+ // warning IL2026 : MyLibrary.Method: Using method 'MyLibrary.DynamicBehavior'
+ // which has 'RequiresUnreferencedCodeAttribute' can break functionality
+ // when trimming application code.
+ DynamicBehavior();
+ }
+
+ [RequiresUnreferencedCode(
+ "DynamicBehavior is incompatible with trimming.")]
+ static void DynamicBehavior()
+ {
+ }
+}
+//
+#elif RequiresUnreferencedCode
+//
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
{
- public class Class1
+ [RequiresUnreferencedCode("Calls DynamicBehavior.")]
+ public static void Method()
{
+ DynamicBehavior();
+ }
+ [RequiresUnreferencedCode(
+ "DynamicBehavior is incompatible with trimming.")]
+ static void DynamicBehavior()
+ {
}
-}
\ No newline at end of file
+}
+//
+#endif
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
index ef1c47ad7ad3e..516fdabb2def9 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
@@ -1,15 +1,16 @@
- net8.0
- enable
- enable
+ Exe
+ net7.0
+ true
+ full
-
-
- true
-
-
-
+
+
+
+
+
+
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt
new file mode 100644
index 0000000000000..ef1c47ad7ad3e
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+ true
+
+
+
+
diff --git a/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj b/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj
new file mode 100644
index 0000000000000..d0d70bd752cc6
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+
+ net6.0
+ true
+
+ link
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/core/deploying/trimming/snippets/MyTestLib6app/Program.cs b/docs/core/deploying/trimming/snippets/MyTestLib6app/Program.cs
new file mode 100644
index 0000000000000..f2b11fd28b1c7
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyTestLib6app/Program.cs
@@ -0,0 +1,2 @@
+// See https://aka.ms/new-console-template for more information
+System.Console.WriteLine("Hello, World!");
From 2276a524e417f76e655251121121a8d76762fc16 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 14:59:26 -1000
Subject: [PATCH 10/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 32 ++-------------
.../trimming/snippets/MyLibrary/Class1.cs | 39 ++++++++++++++++++-
2 files changed, 41 insertions(+), 30 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 1554254658653..cdb0b4646522a 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -153,37 +153,11 @@ Once you have "bubbled up" the attribute all the way to public APIs (so that the
### DynamicallyAccessedMembers
-```csharp
-using System.Diagnostics.CodeAnalysis;
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA1" highlight="5":::
-public class MyLibrary
-{
- static void UseMethods(Type type)
- {
- // warning IL2070: MyLibrary.UseMethods(Type): 'this' argument does not satisfy
- // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
- // 'System.Type.GetMethods()'.
- // The parameter 't' of method 'MyLibrary.UseMethods(Type)' doesn't have
- // matching annotations.
- foreach (var method in type.GetMethods())
- {
- // ...
- }
- }
-}
-```
+In the preceding code, `UseMethods` is calling a reflection method that has a requirement. The requirement states that the type's public methods are available. Satisfy the requirement by adding the same requirement to the parameter of `UseMethods`.
-Here, `UseMethods` is calling a reflection method that has a requirement. The requirement states that the type's public methods are available. In this case, you can satisfy the requirement by adding the same requirement to the parameter of `UseMethods`.
-
-```csharp
-static void UseMethods(
- // State the requirement in the UseMethods parameter.
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- Type type)
-{
- // ...
-}
-```
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2" highlight="8":::
Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the `PublicMethods` requirement. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you're done.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 411eba0680e05..3f668c753b17c 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,4 +1,4 @@
-#define RequiresUnreferencedCode // FIRST RequiresUnreferencedCode
+#define DAA2// FIRST RequiresUnreferencedCode DAA1 DAA2
#if NEVER
#elif FIRST
//
@@ -40,4 +40,41 @@ static void DynamicBehavior()
}
}
//
+#elif DAA1
+//
+using System;
+
+public class MyLibrary
+{
+ static void UseMethods(Type type)
+ {
+ // warning IL2070: MyLibrary.UseMethods(Type): 'this' argument does not satisfy
+ // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
+ // 'System.Type.GetMethods()'.
+ // The parameter 't' of method 'MyLibrary.UseMethods(Type)' doesn't have
+ // matching annotations.
+ foreach (var method in type.GetMethods())
+ {
+ // ...
+ }
+ }
+}
+//
+#elif DAA2
+//
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
+{
+ static void UseMethods(
+ // State the requirement in the UseMethods parameter.
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ Type type)
+ {
+ // ...
+ }
+}
+//
+
#endif
From 75a2fddfadb4bb67eb94b0c526b7ba7aad7f26c4 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 15:10:01 -1000
Subject: [PATCH 11/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 25 ++----------
.../trimming/snippets/MyLibrary/Class1.cs | 40 ++++++++++++++++++-
2 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index cdb0b4646522a..3f59507acf0ed 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -161,32 +161,13 @@ In the preceding code, `UseMethods` is calling a reflection method that has a , and produces further warnings.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 3f668c753b17c..721583e51389f 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,4 +1,4 @@
-#define DAA2// FIRST RequiresUnreferencedCode DAA1 DAA2
+#define UMH2 // FIRST RequiresUnreferencedCode DAA1 DAA2 UMH UMH2
#if NEVER
#elif FIRST
//
@@ -76,5 +76,43 @@ static void UseMethods(
}
}
//
+#elif UMH
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
+{
+ private static void UseMethods(object type) => throw new NotImplementedException();
+
+ //
+
+ static Type type;
+ static void UseMethodsHelper()
+ {
+ // warning IL2077: MyLibrary.UseMethodsHelper(Type): 'type' argument does not satisfy
+ // 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
+ // 'MyLibrary.UseMethods(Type)'.
+ // The field 'System.Type MyLibrary::type' does not have matching annotations.
+ UseMethods(type);
+ }
+ //
+}
+
+#elif UMH2
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
+{
+ //
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ static Type type;
+
+ static void InitializeTypeField()
+ {
+ MyLibrary.type = typeof(System.Tuple);
+ }
+ //
+}
#endif
From bb1f7ce75d86b68632ce386787ab52bbc70561bd Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 16:27:35 -1000
Subject: [PATCH 12/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 128 ++++-----------
.../trimming/snippets/MyLibrary/Class1.cs | 151 +++++++++++++++++-
.../snippets/MyLibrary/ContainingType.cs | 3 +
.../snippets/MyLibrary/GenericType.cs | 3 +
4 files changed, 186 insertions(+), 99 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/ContainingType.cs
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/GenericType.cs
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 3f59507acf0ed..1ca1b1eaf6496 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -173,133 +173,65 @@ In this case, the trim analysis keeps public methods of , and
## Recommendations
-In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it's reachable only from a small part of the library.
+Avoid reflection when possible. When using reflection, minimized reflection scope so that it's reachable only from a small part of the library.
-- Avoid using non-understood patterns in places like static constructors that result in the warning propagating to all members of the class.
-- Avoid annotating virtual methods or interface methods, which will require all overrides to have matching annotations.
-- In some cases, you're able to mechanically propagate warnings through your code without issues. Sometimes this results in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis.
-- In other cases, you might discover that your code uses patterns that can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern.
-- Sometimes the existing design of an API renders it mostly trim-incompatible, and you may need to find other ways to accomplish what it's doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed.
+* Avoid using non-understood patterns in places like static constructors. Static constructors result in the warning propagating to all members of the class.
+* Avoid annotating virtual methods or interface methods, which requires all overrides to have matching annotations.
+* In some cases, you're able to mechanically propagate warnings through your code without issues. Sometimes this results in much of your public API being annotated with `RequiresUnreferencedCode`. Annotating with `RequiresUnreferencedCode` is the right thing to do if the library behaves in ways that can't be understood statically by the trim analysis.
+
+* Code that uses patterns that can't be expressed in terms of the `DynamicallyAccessedMembers` attributes:
+ * Consider reorganizing that code to make it follow an analyzable pattern. This also applies to code that only uses reflection to operate on statically known types.
+* If an API is mostly trim-incompatible, you may need to find other ways to write the API. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. For example, see [How to use source generation in System.Text.Json](/dotnet/standard/serialization/system-text-json/source-generation)
## Resolve warnings for non-analyzable patterns
It's better to resolve warnings by expressing the intent of your code using `RequiresUnreferencedCode` and `DynamicallyAccessedMembers` when possible. However, in some cases, you may be interested in enabling trimming of a library that uses patterns that can't be expressed with those attributes, or without refactoring existing code. This section describes some advanced ways to resolve trim analysis warnings.
> [!WARNING]
-> These techniques might break your code if used incorrectly.
+> These techniques might change the behavior or your code or result in run time exceptions if used incorrectly.
### UnconditionalSuppressMessage
-If the intent of your code can't be expressed with the annotations, but you know that the warning doesn't represent a real issue at run time, you can suppress the warnings using . This is similar to `SuppressMessageAttribute`, but it's persisted in IL and respected during trim analysis.
+Consider code that:
+
+* The intent can't be expressed with the annotations.
+* Generates a warning but doesn't represent a real issue at run time.
+
+The warnings can be suppressed . This is similar to `SuppressMessageAttribute`, but it's persisted in IL and respected during trim analysis.
> [!WARNING]
-> When suppressing warnings, you are responsible for guaranteeing the trim compatibility of your code based on invariants that you know to be true by inspection. Be careful with these annotations, because if they are incorrect, or if invariants of your code change, they might end up hiding real issues.
+> When suppressing warnings, you are responsible for guaranteeing the trim compatibility of the code based on invariants that you know to be true by inspection and testing. Use caution with these annotations, because if they are incorrect, or if invariants of your code change, they might end up hiding incorrect code.
For example:
-```csharp
-class TypeCollection
-{
- Type[] types;
-
- // Ensure that only types with preserved constructors are stored in the array
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
- public Type this[int i]
- {
- // warning IL2063: TypeCollection.Item.get: Value returned from method 'TypeCollection.Item.get'
- // can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.
- get => types[i];
- set => types[i] = value;
- }
-}
-
-class TypeCreator
-{
- TypeCollection types;
-
- public void CreateType(int i)
- {
- types[i] = typeof(TypeWithConstructor);
- Activator.CreateInstance(types[i]); // No warning!
- }
-}
-
-class TypeWithConstructor
-{
-}
-```
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD1" highlight="7":::
Here, the indexer property has been annotated so that the returned `Type` meets the requirements of `CreateInstance`. This already ensures that the `TypeWithConstructor` constructor is kept, and that the call to `CreateInstance` doesn't warn. Furthermore, the indexer setter annotation ensures that any types stored in the `Type[]` have a constructor. However, the analysis isn't able to see this, and still produces a warning for the getter, because it doesn't know that the returned type has its constructor preserved.
If you're sure that the requirements are met, you can silence this warning by adding `UnconditionalSuppressMessage` to the getter:
-```csharp
-[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
-public Type this[int i]
-{
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
- Justification = "The list only contains types stored through the annotated setter.")]
- get => types[i];
- set => types[i] = value;
-}
-```
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD2" highlight="9-10":::
-It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was simply a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-
-```csharp
-[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
- // Invalid justification and suppression: property being non-reflectively
- // used by the app doesn't guarantee that the property will be available
- // for reflection. Properties that are not visible targets of reflection
- // are already optimized away with Native AOT trimming and may be
- // optimized away for non-native deployment in the future as well.
- Justification = "*INVALID* Only need to serialize properties that are used by the app. *INVALID*")]
-public string Serialize(object o)
-{
- StringBuilder sb = new StringBuilder();
- foreach (var property in o.GetType().GetProperties())
- {
- AppendProperty(sb, property, o);
- }
- return sb.ToString();
-}
-```
+It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
+
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="9-10":::
### DynamicDependency
-This attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes, which inform the trim analysis about the reflection behavior of your code, `DynamicDependency` only keeps other members. This can be used together with `UnconditionalSuppressMessageAttribute` to fix some analysis warnings.
+The [`[DynamicDependency]`](xref:System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute) attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes, which inform the trim analysis about the reflection behavior of the code, `[DynamicDependency]` only keeps other members. This can be used together with [`[UnconditionalSuppressMessage]`](xref:System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute) to fix some analysis warnings.
> [!WARNING]
-> Use `DynamicDependencyAttribute` only as a last resort when the other approaches aren't viable. It is preferable to express the reflection behavior of your code using `RequiresUnreferencedCodeAttribute` or `DynamicallyAccessedMembersAttribute`.
-
-```csharp
-[DynamicDependency("Helper", "MyType", "MyAssembly")]
-static void RunHelper()
-{
- var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
- helper.Invoke(null, null);
-}
-```
+> Use `[DynamicDependency]` attribute only as a last resort when the other approaches aren't viable. It is preferable to express the reflection behavior using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) or [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute):
+
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD4" highlight="1":::
Without `DynamicDependency`, trimming might remove `Helper` from `MyAssembly` or remove `MyAssembly` completely if it's not referenced elsewhere, producing a warning that indicates a possible failure at run time. The attribute ensures that `Helper` is kept.
The attribute specifies the members to keep via a `string` or via `DynamicallyAccessedMemberTypes`. The type and assembly are either implicit in the attribute context, or explicitly specified in the attribute (by `Type`, or by `string`s for the type and assembly name).
-The type and member strings use a variation of the C# documentation comment ID string [format](/dotnet/csharp/language-reference/language-specification/documentation-comments#id-string-format), without the member prefix. The member string shouldn't include the name of the declaring type, and may omit parameters to keep all members of the specified name. Some examples of the format follow:
-
-```csharp
-[DynamicDependency("Method()")]
-[DynamicDependency("Method(System,Boolean,System.String)")]
-[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
-[DynamicDependency("MemberName")]
-[DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
-[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
-// generics
-[DynamicDependency("GenericMethodName``1")]
-[DynamicDependency("GenericMethod``2(``0,``1)")]
-[DynamicDependency("MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
-[DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
-[DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]
-```
+The type and member strings use a variation of the C# documentation comment ID string [format](/dotnet/csharp/language-reference/language-specification/documentation-comments#id-string-format), without the member prefix. The member string shouldn't include the name of the declaring type, and may omit parameters to keep all members of the specified name. Some examples of the format are shown in the following code:
+
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD5":::
-This attribute is designed to be used in cases where a method contains reflection patterns that can't be analyzed even with the help of `DynamicallyAccessedMembersAttribute`.
+The `[DynamicDependency]` attribute is designed to be used in cases where a method contains reflection patterns that can't be analyzed even with the help of `DynamicallyAccessedMembersAttribute`.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 721583e51389f..28666cd636a69 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,4 +1,4 @@
-#define UMH2 // FIRST RequiresUnreferencedCode DAA1 DAA2 UMH UMH2
+#define AD5 // FIRST RequiresUnreferencedCode DAA1 DAA2 UMH UMH2 AD1 AD2 AD3 AD4 AD5
#if NEVER
#elif FIRST
//
@@ -115,4 +115,153 @@ static void InitializeTypeField()
//
}
+#elif AD1
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
+{
+ //
+ class TypeCollection
+ {
+ Type[] types;
+
+ // Ensure that only types with preserved constructors are stored in the array
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
+ public Type this[int i]
+ {
+ // warning IL2063: TypeCollection.Item.get: Value returned from method
+ // 'TypeCollection.Item.get' can't be statically determined and may not meet
+ // 'DynamicallyAccessedMembersAttribute' requirements.
+ get => types[i];
+ set => types[i] = value;
+ }
+ }
+
+ class TypeCreator
+ {
+ TypeCollection types;
+
+ public void CreateType(int i)
+ {
+ types[i] = typeof(TypeWithConstructor);
+ Activator.CreateInstance(types[i]); // No warning!
+ }
+ }
+
+ class TypeWithConstructor
+ {
+ }
+ //
+}
+
+#elif AD2
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+public class MyLibrary
+{
+ //
+ class TypeCollection
+ {
+ Type[] types;
+
+ // Ensure that only types with preserved constructors are stored in the array
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
+ public Type this[int i]
+ {
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
+ Justification = "The list only contains types stored through the annotated setter.")]
+ get => types[i];
+ set => types[i] = value;
+ }
+ }
+
+ class TypeCreator
+ {
+ TypeCollection types;
+
+ public void CreateType(int i)
+ {
+ types[i] = typeof(TypeWithConstructor);
+ Activator.CreateInstance(types[i]); // No warning!
+ }
+ }
+
+ class TypeWithConstructor
+ {
+ }
+ //
+}
+#elif AD3
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using System.Text;
+
+public class MyLibrary
+{
+ //
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
+ // Invalid justification and suppression: property being non-reflectively
+ // used by the app doesn't guarantee that the property will be available
+ // for reflection. Properties that are not visible targets of reflection
+ // are already optimized away with Native AOT trimming and may be
+ // optimized away for non-native deployment in the future as well.
+ Justification = "*INVALID* Only need to serialize properties that are used by"
+ + "the app. *INVALID*")]
+ public string Serialize(object o)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach (var property in o.GetType().GetProperties())
+ {
+ AppendProperty(sb, property, o);
+ }
+ return sb.ToString();
+ }
+ //
+ private void AppendProperty(StringBuilder sb, PropertyInfo property, object o) => throw new NotImplementedException();
+ }
+#elif AD4
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+public class MyLibrary
+{
+ //
+ [DynamicDependency("Helper", "MyType", "MyAssembly")]
+ static void RunHelper()
+ {
+ var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
+ helper.Invoke(null, null);
+ }
+}
+//
+#elif AD5
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+public class MyLibrary
+{
+ //
+ [DynamicDependency("Method()")]
+ [DynamicDependency("Method(System,Boolean,System.String)")]
+ [DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
+ [DynamicDependency("MemberName")]
+ [DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
+ [DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
+ // generics
+ [DynamicDependency("GenericMethodName``1")]
+ [DynamicDependency("GenericMethod``2(``0,``1)")]
+ [DynamicDependency("MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
+ [DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
+ [DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]
+ //
+ static void RunHelper()
+ {
+ var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
+ helper.Invoke(null, null);
+ }
+}
+
#endif
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/ContainingType.cs b/docs/core/deploying/trimming/snippets/MyLibrary/ContainingType.cs
new file mode 100644
index 0000000000000..c6ffe33fd9e6f
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/ContainingType.cs
@@ -0,0 +1,3 @@
+internal class ContainingType
+{
+}
\ No newline at end of file
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/GenericType.cs b/docs/core/deploying/trimming/snippets/MyLibrary/GenericType.cs
new file mode 100644
index 0000000000000..4cb718a654553
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/GenericType.cs
@@ -0,0 +1,3 @@
+internal class GenericType
+{
+}
\ No newline at end of file
From bdc17f1a2e054e8ad164a339338a83807f061f47 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 16:52:27 -1000
Subject: [PATCH 13/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 21 +++++++++----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 1ca1b1eaf6496..0fb7e9ab8e1de 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -8,7 +8,7 @@ ms.date: 06/12/2023
# Prepare .NET libraries for trimming
-The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md), which removes unused code from the app and its dependencies. Not all code is compatible with trimming, so .NET 6 provides trim analysis warnings to detect patterns that may break trimmed apps. To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). This article describes how to prepare libraries for trimming with the aid of these warnings, including recommendations for fixing some common cases.
+The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md). Trimming removes unused code from the app and its dependencies. Not all code is compatible with trimming, so .NET provides trim analysis warnings to detect patterns that may break trimmed apps. To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). This article describes how to prepare libraries for trimming and provides recommendations for fixing some common cases.
## Prerequisites
@@ -19,7 +19,7 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
Trim warnings in a library can be found with either of the following methods:
* Enabling project-specific trimming using the `IsTrimmable` property.
-* Added the library as a reference to a sample app, and trim the sample app.
+* Creating a sample app that uses the library, and enabling trimming for the sample app.
We recommend using both approaches. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a sample app is more work, but shows all warnings.
@@ -63,14 +63,14 @@ When building and publishing a library:
* The implementations of the dependencies aren't available.
* The available reference assemblies don't have enough information for the trimmer to determine if they're compatible with trimming.
-Because the dependency limitations, a self-contained sample app which uses the libary and it's dependencies must be created. The sample app executable includes all the information the trimmer requires to issue warning on trim incompatibilities in:
+Because of the dependency limitations, a self-contained sample app which uses the library and its dependencies must be created. The sample app executable includes all the information the trimmer requires to issue warning on trim incompatibilities in:
* The library code.
* The code that the library references from its dependencies.
-***Note:*** If the library has significantly different behavior depending on the target framework, create a sample app for each of the target frameworks. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
+***Note:*** If the library has different behavior depending on the target framework, create a sample app for each of the target frameworks. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
-To create the sample app, create a separate console application project with `dotnet new console` and modify the project file to look like the following. You need to do the following in your project file:
+To create the sample app, create a separate console application project with `dotnet new console` and modify the project similar to project shown below. You need to do the following in the project file:
* Add `true`.
* Add a reference to the library project with ``.
@@ -78,7 +78,6 @@ To create the sample app, create a separate console application project with `do
* `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root,". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
* If your app targets .NET 6, set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
- *
##### .csproj file
@@ -167,7 +166,7 @@ In the following example, an unknown `Type` flows into the annotated method para
Similarly, here the problem is that the field `type` is passed into a parameter with these requirements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This warns about code that assigns incompatible values to the field instead. Sometimes this process continues until a public API is annotated, and other times it ends when a concrete type flows into a location with these requirements. For example:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_UMH2" highlight="7":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_UMH2" highlight="1":::
In this case, the trim analysis keeps public methods of , and produces further warnings.
@@ -205,13 +204,13 @@ The warnings can be suppressed
Date: Wed, 2 Aug 2023 20:13:23 -1000
Subject: [PATCH 14/57] Update trimming doc
---
.../trimming/snippets/MyLibrary/Class1.cs | 74 +++++--------------
1 file changed, 18 insertions(+), 56 deletions(-)
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 28666cd636a69..9f39545669f2d 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,8 +1,8 @@
-#define AD5 // FIRST RequiresUnreferencedCode DAA1 DAA2 UMH UMH2 AD1 AD2 AD3 AD4 AD5
-#if NEVER
-#elif FIRST
-//
+//
using System.Diagnostics.CodeAnalysis;
+using System;
+using System.Text;
+using System.Reflection;
public class MyLibrary
{
@@ -21,11 +21,9 @@ static void DynamicBehavior()
}
}
//
-#elif RequiresUnreferencedCode
-//
-using System.Diagnostics.CodeAnalysis;
-public class MyLibrary
+//
+public class MyLibrary2
{
[RequiresUnreferencedCode("Calls DynamicBehavior.")]
public static void Method()
@@ -40,11 +38,9 @@ static void DynamicBehavior()
}
}
//
-#elif DAA1
-//
-using System;
-public class MyLibrary
+//
+public class MyLibrary3
{
static void UseMethods(Type type)
{
@@ -59,13 +55,8 @@ static void UseMethods(Type type)
}
}
}
-//
-#elif DAA2
-//
-using System;
-using System.Diagnostics.CodeAnalysis;
-public class MyLibrary
+public class MyLibrary4
{
static void UseMethods(
// State the requirement in the UseMethods parameter.
@@ -75,17 +66,12 @@ static void UseMethods(
// ...
}
}
-//
-#elif UMH
-using System;
-using System.Diagnostics.CodeAnalysis;
-public class MyLibrary
+public class MyLibrary5
{
private static void UseMethods(object type) => throw new NotImplementedException();
//
-
static Type type;
static void UseMethodsHelper()
{
@@ -98,11 +84,7 @@ static void UseMethodsHelper()
//
}
-#elif UMH2
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-public class MyLibrary
+public class MyLibrary6
{
//
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
@@ -115,11 +97,7 @@ static void InitializeTypeField()
//
}
-#elif AD1
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-public class MyLibrary
+public class MyLibrary7
{
//
class TypeCollection
@@ -155,11 +133,7 @@ class TypeWithConstructor
//
}
-#elif AD2
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-public class MyLibrary
+public class MyLibrary8
{
//
class TypeCollection
@@ -193,13 +167,8 @@ class TypeWithConstructor
}
//
}
-#elif AD3
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using System.Text;
-public class MyLibrary
+public class MyLibrary11
{
//
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
@@ -209,7 +178,7 @@ public class MyLibrary
// are already optimized away with Native AOT trimming and may be
// optimized away for non-native deployment in the future as well.
Justification = "*INVALID* Only need to serialize properties that are used by"
- + "the app. *INVALID*")]
+ + "the app. *INVALID*")]
public string Serialize(object o)
{
StringBuilder sb = new StringBuilder();
@@ -221,12 +190,9 @@ public string Serialize(object o)
}
//
private void AppendProperty(StringBuilder sb, PropertyInfo property, object o) => throw new NotImplementedException();
- }
-#elif AD4
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
+}
-public class MyLibrary
+public class MyLibrary12
{
//
[DynamicDependency("Helper", "MyType", "MyAssembly")]
@@ -237,11 +203,7 @@ static void RunHelper()
}
}
//
-#elif AD5
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-
-public class MyLibrary
+public class MyLibrary22
{
//
[DynamicDependency("Method()")]
From 97a56572a4db0d1224d26d1ecb9b2c023fc8870d Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 2 Aug 2023 20:18:09 -1000
Subject: [PATCH 15/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 22 +------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 0fb7e9ab8e1de..b9fee46be9f6b 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -78,33 +78,13 @@ To create the sample app, create a separate console application project with `do
* `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root,". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
* If your app targets .NET 6, set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
-
##### .csproj file
### [.NET 6](#tab/net6)
Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
-```xml
-
-
-
- Exe
-
- net6.0
- true
-
- link
-
-
-
-
-
-
-
-
-
-```
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj":::
### [.NET 7+](#tab/net7plus)
From ba9b9f70a7a87f5979b6b20482a71d4a5e065d25 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 3 Aug 2023 12:09:33 -1000
Subject: [PATCH 16/57] Update trimming doc
---
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 9f39545669f2d..24d3e83b98079 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -225,5 +225,3 @@ static void RunHelper()
helper.Invoke(null, null);
}
}
-
-#endif
From c4e63d573e443a22fe75344112ee1bf18bcdc5d7 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 3 Aug 2023 13:54:31 -1000
Subject: [PATCH 17/57] Update trimming doc
---
.../trimming/snippets/MyLibrary/Class1.cs | 4 +++-
.../trimming/snippets/MyLibrary/MyLibrary.csproj | 13 +++----------
.../snippets/MyLibrary/MyLibrary.csproj.xml | 16 ++++++++++++++++
3 files changed, 22 insertions(+), 11 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 24d3e83b98079..df7ae8d02586d 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -6,6 +6,8 @@
public class MyLibrary
{
+ internal static Type type;
+
public static void Method()
{
// warning IL2026 : MyLibrary.Method: Using method 'MyLibrary.DynamicBehavior'
@@ -87,8 +89,8 @@ static void UseMethodsHelper()
public class MyLibrary6
{
//
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static Type type;
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static void InitializeTypeField()
{
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
index 516fdabb2def9..446a24cdc144f 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
@@ -1,16 +1,9 @@
- Exe
net7.0
- true
- full
+ enable
+ enable
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
new file mode 100644
index 0000000000000..516fdabb2def9
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net7.0
+ true
+ full
+
+
+
+
+
+
+
+
+
From ea48fd50b2ed829981dafd711deae58fdb20f88b Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 3 Aug 2023 14:25:56 -1000
Subject: [PATCH 18/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 2 +-
.../trimming/snippets/MyLibrary/Class1.cs | 3 +++
.../snippets/MyLibrary/MyLibrary.csproj.txt | 15 ---------------
.../snippets/MyLibrary/MyLibrary.csproj.xml | 19 +++++++++----------
4 files changed, 13 insertions(+), 26 deletions(-)
delete mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index b9fee46be9f6b..d3b51fdc40a33 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -40,7 +40,7 @@ Set `true` in the project file.
---
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt" id="snippet" highlight="2":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml" id="snippet" highlight="2":::
Setting `true` marks the assembly as "trimmable" and enables trim warnings. "trimmable" means the project:
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index df7ae8d02586d..aa572293eba95 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -57,9 +57,11 @@ static void UseMethods(Type type)
}
}
}
+//
public class MyLibrary4
{
+ //
static void UseMethods(
// State the requirement in the UseMethods parameter.
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
@@ -67,6 +69,7 @@ static void UseMethods(
{
// ...
}
+ //
}
public class MyLibrary5
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt
deleted file mode 100644
index ef1c47ad7ad3e..0000000000000
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
-
-
-
- true
-
-
-
-
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
index 516fdabb2def9..ef1c47ad7ad3e 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
@@ -1,16 +1,15 @@
- Exe
- net7.0
- true
- full
+ net8.0
+ enable
+ enable
-
-
-
-
-
-
+
+
+ true
+
+
+
From aa0429e0da37a140370a346049a8b118c557f8d5 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 3 Aug 2023 14:34:53 -1000
Subject: [PATCH 19/57] Update trimming doc
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index d3b51fdc40a33..b41dfce4a81ba 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -95,7 +95,7 @@ Use the [.NET 7 and higher default behavior](../../../core/compatibility/deploym
* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option, warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "Tue")]`, including parts that are unused by the library.
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.txt":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml":::
Note: In the preceding project file, when using .NET 8, replace `net7.0` with `net8.0`.
From 26ff3cb72518dc74543fa0689663bc0be50b6b19 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 3 Aug 2023 15:28:47 -1000
Subject: [PATCH 20/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 61 +++++++++++--------
.../trimming/snippets/MyLibrary/Class1.cs | 10 ++-
2 files changed, 40 insertions(+), 31 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index b41dfce4a81ba..870d64f4900d6 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -8,7 +8,10 @@ ms.date: 06/12/2023
# Prepare .NET libraries for trimming
-The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md). Trimming removes unused code from the app and its dependencies. Not all code is compatible with trimming, so .NET provides trim analysis warnings to detect patterns that may break trimmed apps. To resolve warnings originating from the app code, see [resolving trim warnings](#resolve-trim-warnings). This article describes how to prepare libraries for trimming and provides recommendations for fixing some common cases.
+The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md). Trimming removes unused code from the app and its dependencies. Not all code is compatible with trimming. .NET provides trim analysis warnings to detect patterns that may break trimmed apps. This article:
+
+* Describes how to prepare libraries for trimming.
+* Provides recommendations for fixing [common trimming warnings](#resolve-trim-warnings).
## Prerequisites
@@ -19,9 +22,9 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
Trim warnings in a library can be found with either of the following methods:
* Enabling project-specific trimming using the `IsTrimmable` property.
-* Creating a sample app that uses the library, and enabling trimming for the sample app.
+* Creating a trimming test app that uses all the APIs in the library, and enabling trimming for the test app.
-We recommend using both approaches. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a sample app is more work, but shows all warnings.
+We recommend using both approaches. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a test app is more work, but shows all warnings.
### Enable project-specific trimming
@@ -51,7 +54,7 @@ The `IsTrimmable` property defaults to `true` when configuring a project as AOT-
To generate trim warnings without marking the project as trim-compatible, use `true` rather than `true`.
-### Show all warnings with sample app
+### Show all warnings with test app
To show all analysis warnings for a library, the trimmer must analyze the implementation:
@@ -63,20 +66,24 @@ When building and publishing a library:
* The implementations of the dependencies aren't available.
* The available reference assemblies don't have enough information for the trimmer to determine if they're compatible with trimming.
-Because of the dependency limitations, a self-contained sample app which uses the library and its dependencies must be created. The sample app executable includes all the information the trimmer requires to issue warning on trim incompatibilities in:
+Because of the dependency limitations, a self-contained test app which uses the library and its dependencies must be created. The test app executable includes all the information the trimmer requires to issue warning on trim incompatibilities in:
* The library code.
* The code that the library references from its dependencies.
-***Note:*** If the library has different behavior depending on the target framework, create a sample app for each of the target frameworks. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
+***Note:*** If the library has different behavior depending on the target framework, create a trimming test app for each of the target frameworks. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
+
+To create the trimming test app:
-To create the sample app, create a separate console application project with `dotnet new console` and modify the project similar to project shown below. You need to do the following in the project file:
+* Create a separate console application project with `dotnet new console`.
+* Add a reference to the library.
+* Add calls to each API in the library.
+* Modify the project similar to project shown below using the following list:
-* Add `true`.
-* Add a reference to the library project with ``.
-* Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root,". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
-* If your app targets .NET 6, set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
+ * Add `true`.
+ * Add a reference to the library project with ``.
+ * Specify the library as a trimmer root assembly with ``.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
##### .csproj file
@@ -88,12 +95,13 @@ Set the `TrimmerDefaultAction` property to `link` with `li
### [.NET 7+](#tab/net7plus)
-Use the [.NET 7 and higher default behavior](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md), which can enforce the behavior by adding `full`.
-
-`full`:
+The `full` setting:
+* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
-* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option, warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "Tue")]`, including parts that are unused by the library.
+* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
+ * Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "Tue")]`
+ * The preceding warnings can be issued by parts that are unused by the library.
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml":::
@@ -107,7 +115,7 @@ Once the project file is updated, run `dotnet publish` with the target [runtime
dotnet publish -c Release -r
```
-Follow the same pattern for multiple libraries. To see trim analysis warnings for more than one library at a time, add them all to the same project as `ProjectReference` and `TrimmerRootAssembly` items. Adding all the libraries to the same project with `ProjectReference` and `TrimmerRootAssembly` items warns about dependencies if ***any*** of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only.
+Follow the preceding pattern for multiple libraries. To see trim analysis warnings for more than one library at a time, add them all to the same project as `ProjectReference` and `TrimmerRootAssembly` items. Adding all the libraries to the same project with `ProjectReference` and `TrimmerRootAssembly` items warns about dependencies if ***any*** of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only.
***Note:*** The analysis results depend on the implementation details of the dependencies. Updating to a new version of a dependency may introduce analysis warnings:
@@ -122,23 +130,26 @@ The preceding steps produce warnings about code that may cause problems when use
### RequiresUnreferencedCode
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="5-11":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="17-18":::
+
+This means the library calls a method that has explicitly been annotated as incompatible with trimming, using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` which propagates up the call stack the warning so that callers of `Method` get a warning instead:
-This means the library calls a method that has explicitly been annotated as incompatible with trimming, using . To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` as well; this will "bubble up" the warning so that callers of `Method` get a warning instead:
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode":::
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode" highlight="5":::
+Once you have propagated up the attribute all the way to public API, apps calling the library:
-Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you're done. Apps that call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`.
+* Get warnings only for public methods that aren't trimmable.
+* Don't get warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`.
### DynamicallyAccessedMembers
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA1" highlight="5":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA1":::
-In the preceding code, `UseMethods` is calling a reflection method that has a requirement. The requirement states that the type's public methods are available. Satisfy the requirement by adding the same requirement to the parameter of `UseMethods`.
+In the preceding code, `UseMethods` is calling a reflection method that has a [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute) requirement. The requirement states that the type's public methods are available. Satisfy the requirement by adding the same requirement to the parameter of `UseMethods`.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2" highlight="8":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2" highlight="3":::
-Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the `PublicMethods` requirement. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you're done.
+Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the requirement. Similar to `RequiresUnreferencedCode`, once you have propagated up such warnings to public APIs, you're done.
In the following example, an unknown `Type` flows into the annotated method parameter. The unknown `Type` is from a field:
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index aa572293eba95..bf84b2d29d5ec 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,8 +1,7 @@
//
using System.Diagnostics.CodeAnalysis;
-using System;
-using System.Text;
using System.Reflection;
+using System.Text;
public class MyLibrary
{
@@ -11,8 +10,8 @@ public class MyLibrary
public static void Method()
{
// warning IL2026 : MyLibrary.Method: Using method 'MyLibrary.DynamicBehavior'
- // which has 'RequiresUnreferencedCodeAttribute' can break functionality
- // when trimming application code.
+ // which has [RequiresUnreferencedCode] can break functionality
+ // when trimming app code.
DynamicBehavior();
}
@@ -64,8 +63,7 @@ public class MyLibrary4
//
static void UseMethods(
// State the requirement in the UseMethods parameter.
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- Type type)
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
// ...
}
From 6ba2a9ef550cc6014f61bda0eb5069413c71ba13 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 3 Aug 2023 15:43:20 -1000
Subject: [PATCH 21/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 17 +++++++++--------
.../trimming/snippets/MyLibrary/Class1.cs | 4 ++--
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 870d64f4900d6..fe6a22ded350a 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -132,7 +132,7 @@ The preceding steps produce warnings about code that may cause problems when use
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="17-18":::
-This means the library calls a method that has explicitly been annotated as incompatible with trimming, using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `RequiresUnreferencedCode` which propagates up the call stack the warning so that callers of `Method` get a warning instead:
+This means the library calls a method that has explicitly been annotated as incompatible with trimming, using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `Method` get a warning instead:
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode":::
@@ -149,13 +149,13 @@ In the preceding code, `UseMethods` is calling a reflection method that has a [`
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2" highlight="3":::
-Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the requirement. Similar to `RequiresUnreferencedCode`, once you have propagated up such warnings to public APIs, you're done.
+Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the requirement. Similar to `[RequiresUnreferencedCode]`, once you have propagated up such warnings to public APIs, you're done.
In the following example, an unknown `Type` flows into the annotated method parameter. The unknown `Type` is from a field:
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_UMH":::
-Similarly, here the problem is that the field `type` is passed into a parameter with these requirements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This warns about code that assigns incompatible values to the field instead. Sometimes this process continues until a public API is annotated, and other times it ends when a concrete type flows into a location with these requirements. For example:
+Similarly, here the problem is that the field `type` is passed into a parameter with these requirements. It's fixed by adding [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute) to the field. `[DynamicallyAccessedMembers]` warns about code that assigns incompatible values to the field. Sometimes this process continues until a public API is annotated, and other times it ends when a concrete type flows into a location with these requirements. For example:
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_UMH2" highlight="1":::
@@ -163,11 +163,12 @@ In this case, the trim analysis keeps public methods of , and
## Recommendations
-Avoid reflection when possible. When using reflection, minimized reflection scope so that it's reachable only from a small part of the library.
+***Avoid*** reflection when possible.
-* Avoid using non-understood patterns in places like static constructors. Static constructors result in the warning propagating to all members of the class.
-* Avoid annotating virtual methods or interface methods, which requires all overrides to have matching annotations.
-* In some cases, you're able to mechanically propagate warnings through your code without issues. Sometimes this results in much of your public API being annotated with `RequiresUnreferencedCode`. Annotating with `RequiresUnreferencedCode` is the right thing to do if the library behaves in ways that can't be understood statically by the trim analysis.
+* When using reflection, minimize reflection scope so that it's reachable only from a small part of the library.
+* Avoid using non-trimmable patterns in places like static constructors. Static constructors result in the warning propagating to all members of the class.
+* Avoid annotating virtual methods or interface methods. Annotating virtual or interface methods requires all overrides to have matching annotations.
+* In some cases, you're able to mechanically propagate warnings through the library code without issues. Sometimes this results in much of your public API being annotated with [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). Annotating with `[RequiresUnreferencedCode]` is the right thing to do if the library behaves in ways that can't be understood statically by the trim analysis.
* Code that uses patterns that can't be expressed in terms of the `DynamicallyAccessedMembers` attributes:
@@ -176,7 +177,7 @@ Avoid reflection when possible. When using reflection, minimized reflection scop
## Resolve warnings for non-analyzable patterns
-It's better to resolve warnings by expressing the intent of your code using `RequiresUnreferencedCode` and `DynamicallyAccessedMembers` when possible. However, in some cases, you may be interested in enabling trimming of a library that uses patterns that can't be expressed with those attributes, or without refactoring existing code. This section describes some advanced ways to resolve trim analysis warnings.
+It's better to resolve warnings by expressing the intent of your code using `[RequiresUnreferencedCode]` and `DynamicallyAccessedMembers` when possible. However, in some cases, you may be interested in enabling trimming of a library that uses patterns that can't be expressed with those attributes, or without refactoring existing code. This section describes some advanced ways to resolve trim analysis warnings.
> [!WARNING]
> These techniques might change the behavior or your code or result in run time exceptions if used incorrectly.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index bf84b2d29d5ec..8d60aaee4a1da 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -63,7 +63,7 @@ public class MyLibrary4
//
static void UseMethods(
// State the requirement in the UseMethods parameter.
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
// ...
}
@@ -90,8 +90,8 @@ static void UseMethodsHelper()
public class MyLibrary6
{
//
- static Type type;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ static Type type;
static void InitializeTypeField()
{
From 440bf8a8cc55b287223858dbae8634ff8c99d3a9 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Fri, 4 Aug 2023 13:33:48 -1000
Subject: [PATCH 22/57] Update trimming doc
---
.../prepare-libraries-for-trimming.md | 40 +++++++++++--------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index fe6a22ded350a..93a9f13dd563c 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -11,7 +11,7 @@ ms.date: 06/12/2023
The .NET SDK makes it possible to reduce the size of self-contained apps by [trimming](trim-self-contained.md). Trimming removes unused code from the app and its dependencies. Not all code is compatible with trimming. .NET provides trim analysis warnings to detect patterns that may break trimmed apps. This article:
* Describes how to prepare libraries for trimming.
-* Provides recommendations for fixing [common trimming warnings](#resolve-trim-warnings).
+* Provides recommendations for [resolving common trimming warnings](#resolve-trim-warnings).
## Prerequisites
@@ -75,37 +75,45 @@ Because of the dependency limitations, a self-contained test app which uses the
To create the trimming test app:
-* Create a separate console application project with `dotnet new console`.
+### [.NET 6](#tab/net6)
+
+* Create a separate console application project.
* Add a reference to the library.
* Add calls to each API in the library.
-* Modify the project similar to project shown below using the following list:
+* Modify the project similar to the project shown below using the following list:
+ * Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
* `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
-##### .csproj file
-
-### [.NET 6](#tab/net6)
-
-Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
-
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj":::
### [.NET 7+](#tab/net7plus)
-The `full` setting:
+* Create a separate console application project.
+* Add a reference to the library.
+* Add calls to each API in the library.
+* Modify the project similar to the project shown below using the following list:
-* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
-* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
-* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
- * Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "Tue")]`
- * The preceding warnings can be issued by parts that are unused by the library.
+ * Add `true`.
+ * Add a reference to the library project with ``.
+ * Specify the library as a trimmer root assembly with ``.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml":::
-Note: In the preceding project file, when using .NET 8, replace `net7.0` with `net8.0`.
+**Notes:**
+
+* In the preceding project file, when using .NET 8, replace `net7.0` with `net8.0`.
+* The `full` setting:
+
+ * Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
+ * Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
+ * Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
+ * Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
+ * The preceding warnings can be issued by parts that are unused by the library.
---
From 5e8ee9b7cbcab453e676c9a4dc9447d8683fd31f Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Fri, 4 Aug 2023 13:34:58 -1000
Subject: [PATCH 23/57] Update trimming doc
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 93a9f13dd563c..9856b48a0b73e 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -75,13 +75,13 @@ Because of the dependency limitations, a self-contained test app which uses the
To create the trimming test app:
-### [.NET 6](#tab/net6)
-
* Create a separate console application project.
* Add a reference to the library.
* Add calls to each API in the library.
* Modify the project similar to the project shown below using the following list:
+### [.NET 6](#tab/net6)
+
* Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
* Add `true`.
* Add a reference to the library project with ``.
@@ -92,11 +92,6 @@ To create the trimming test app:
### [.NET 7+](#tab/net7plus)
-* Create a separate console application project.
-* Add a reference to the library.
-* Add calls to each API in the library.
-* Modify the project similar to the project shown below using the following list:
-
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
From 14a35facd2dc820dcdf123f872464acf79846412 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Fri, 4 Aug 2023 14:03:12 -1000
Subject: [PATCH 24/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 18 ++++++++++++------
.../trimming/snippets/MyLibrary/Class1.cs | 16 ++++++++--------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 9856b48a0b73e..15c4fa2020b3b 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -77,7 +77,7 @@ To create the trimming test app:
* Create a separate console application project.
* Add a reference to the library.
-* Add calls to each API in the library.
+* Add calls to each API in the library.
* Modify the project similar to the project shown below using the following list:
### [.NET 6](#tab/net6)
@@ -86,7 +86,9 @@ To create the trimming test app:
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+
+### .csproj file
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj":::
@@ -95,7 +97,9 @@ To create the trimming test app:
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` would remove the unused library without analyzing it.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+
+### .csproj file
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml":::
@@ -108,7 +112,7 @@ To create the trimming test app:
* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
* Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
- * The preceding warnings can be issued by parts that are unused by the library.
+ * The preceding warnings can be issued by parts that are unused by the library.
---
@@ -126,16 +130,18 @@ Follow the preceding pattern for multiple libraries. To see trim analysis warnin
* Even if there were no API changes.
Introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`.
-
+`
## Resolve trim warnings
The preceding steps produce warnings about code that may cause problems when used in a trimmed app. The following examples show the most common warnings with recommendations for fixing them.
### RequiresUnreferencedCode
+Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) to indicate that the member references code that may be removed by the trimmer.
+
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="17-18":::
-This means the library calls a method that has explicitly been annotated as incompatible with trimming, using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). To get rid of the warning, consider whether `Method` needs to call `DynamicBehavior` to do its job. If so, annotate the caller `Method` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `Method` get a warning instead:
+The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode":::
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 8d60aaee4a1da..e80c2ecb1d201 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -1,15 +1,15 @@
-//
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text;
+//
public class MyLibrary
{
internal static Type type;
- public static void Method()
+ public static void MyMethod()
{
- // warning IL2026 : MyLibrary.Method: Using method 'MyLibrary.DynamicBehavior'
+ // warning IL2026 : MyLibrary.MyMethod: Using 'MyLibrary.DynamicBehavior'
// which has [RequiresUnreferencedCode] can break functionality
// when trimming app code.
DynamicBehavior();
@@ -27,7 +27,7 @@ static void DynamicBehavior()
public class MyLibrary2
{
[RequiresUnreferencedCode("Calls DynamicBehavior.")]
- public static void Method()
+ public static void MyMethod()
{
DynamicBehavior();
}
@@ -43,7 +43,7 @@ static void DynamicBehavior()
//
public class MyLibrary3
{
- static void UseMethods(Type type)
+ static void UseMyMethods(Type type)
{
// warning IL2070: MyLibrary.UseMethods(Type): 'this' argument does not satisfy
// 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
@@ -209,8 +209,8 @@ static void RunHelper()
public class MyLibrary22
{
//
- [DynamicDependency("Method()")]
- [DynamicDependency("Method(System,Boolean,System.String)")]
+ [DynamicDependency("MyMethod()")]
+ [DynamicDependency("MyMethod(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
[DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
From e0cc309f605615ad3bd7e406b9f1a2399935c814 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Fri, 4 Aug 2023 14:15:37 -1000
Subject: [PATCH 25/57] Update trimming doc
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++---
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 15c4fa2020b3b..2abdc8366a330 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -143,7 +143,7 @@ Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System
The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode" highlight="3,9-10":::
Once you have propagated up the attribute all the way to public API, apps calling the library:
@@ -156,11 +156,11 @@ Once you have propagated up the attribute all the way to public API, apps callin
In the preceding code, `UseMethods` is calling a reflection method that has a [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute) requirement. The requirement states that the type's public methods are available. Satisfy the requirement by adding the same requirement to the parameter of `UseMethods`.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2" highlight="3":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2":::
Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the requirement. Similar to `[RequiresUnreferencedCode]`, once you have propagated up such warnings to public APIs, you're done.
-In the following example, an unknown `Type` flows into the annotated method parameter. The unknown `Type` is from a field:
+In the following example, an unknown [Type](/dotnet/api/system.type) flows into the annotated method parameter. The unknown `Type` is from a field:
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_UMH":::
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index e80c2ecb1d201..347a1a7b5acf0 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -62,8 +62,8 @@ public class MyLibrary4
{
//
static void UseMethods(
- // State the requirement in the UseMethods parameter.
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ // State the requirement in the UseMethods parameter.
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
// ...
}
From 6a3f859b5e8bd863a4115279dd65b8c0fa1ed434 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 7 Aug 2023 15:53:13 -1000
Subject: [PATCH 26/57] Update trimming doc
---
.../trimming/prepare-libraries-for-trimming.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 2abdc8366a330..ec42fc892a17a 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -82,11 +82,11 @@ To create the trimming test app:
### [.NET 6](#tab/net6)
- * Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
- * Add `true`.
- * Add a reference to the library project with ``.
- * Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+* Set the `TrimmerDefaultAction` property to `link` with `link` n a `` element.
+* Add `true`.
+* Add a reference to the library project with ``.
+* Specify the library as a trimmer root assembly with ``.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
### .csproj file
@@ -94,10 +94,10 @@ To create the trimming test app:
### [.NET 7+](#tab/net7plus)
- * Add `true`.
- * Add a reference to the library project with ``.
- * Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+* Add `true`.
+* Add a reference to the library project with ``.
+* Specify the library as a trimmer root assembly with ``.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
### .csproj file
From 56aef48552db7952c4de9900e4b58154e0c95bb9 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 7 Aug 2023 16:02:35 -1000
Subject: [PATCH 27/57] Update trimming doc
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index ec42fc892a17a..afdd90e57b59a 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -131,6 +131,7 @@ Follow the preceding pattern for multiple libraries. To see trim analysis warnin
Introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`.
`
+
## Resolve trim warnings
The preceding steps produce warnings about code that may cause problems when used in a trimmed app. The following examples show the most common warnings with recommendations for fixing them.
From 9af16a935605145e539c21f4385107268c28ad00 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 8 Aug 2023 09:05:29 -1000
Subject: [PATCH 28/57] Apply suggestions from code review
Co-authored-by: Sven Boemer
---
.../core/deploying/trimming/prepare-libraries-for-trimming.md | 4 ++--
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index afdd90e57b59a..0fbff37ddc28e 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -97,7 +97,7 @@ To create the trimming test app:
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root". A "root" assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
### .csproj file
@@ -112,7 +112,7 @@ To create the trimming test app:
* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
* Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
- * The preceding warnings can be issued by parts that are unused by the library.
+ * The preceding warnings can be issued for code that is unused by the library.
---
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 347a1a7b5acf0..2d3b8b675acea 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -24,7 +24,7 @@ static void DynamicBehavior()
//
//
-public class MyLibrary2
+public class MyLibrary
{
[RequiresUnreferencedCode("Calls DynamicBehavior.")]
public static void MyMethod()
From f224ea9918b56f50b36e11a377f9f0acf9c7d8cc Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 8 Aug 2023 09:08:36 -1000
Subject: [PATCH 29/57] react to feedback
---
.../prepare-libraries-for-trimming.md | 2 +-
.../trimming/snippets/MyLibrary/Class1.cs | 17 --------------
.../trimming/snippets/MyLibrary/Class2.cs | 22 +++++++++++++++++++
3 files changed, 23 insertions(+), 18 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 0fbff37ddc28e..06cd54b022b2b 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -144,7 +144,7 @@ Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System
The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_RequiresUnreferencedCode" highlight="3,9-10":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs" id="snippet_RequiresUnreferencedCode" highlight="3,9-10":::
Once you have propagated up the attribute all the way to public API, apps calling the library:
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 2d3b8b675acea..982f367ec1c59 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -23,23 +23,6 @@ static void DynamicBehavior()
}
//
-//
-public class MyLibrary
-{
- [RequiresUnreferencedCode("Calls DynamicBehavior.")]
- public static void MyMethod()
- {
- DynamicBehavior();
- }
-
- [RequiresUnreferencedCode(
- "DynamicBehavior is incompatible with trimming.")]
- static void DynamicBehavior()
- {
- }
-}
-//
-
//
public class MyLibrary3
{
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs
new file mode 100644
index 0000000000000..c2c12d000dbdd
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs
@@ -0,0 +1,22 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace MyLibrary2;
+class Class2
+{
+ //
+ public class MyLibrary
+ {
+ [RequiresUnreferencedCode("Calls DynamicBehavior.")]
+ public static void MyMethod()
+ {
+ DynamicBehavior();
+ }
+
+ [RequiresUnreferencedCode(
+ "DynamicBehavior is incompatible with trimming.")]
+ static void DynamicBehavior()
+ {
+ }
+ }
+ //
+}
From 9c2766ab9d96d5bdc5ab944b4627ea717aee1a9b Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 8 Aug 2023 13:45:03 -1000
Subject: [PATCH 30/57] react to feedback
---
.../prepare-libraries-for-trimming.md | 31 +++++++++++--------
.../trimming/snippets/MyLibrary/Class1.cs | 9 ++++--
.../snippets/MyLibrary/MyLibrary.csproj.xml | 4 ++-
3 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 06cd54b022b2b..e16bb2d3ef6ad 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -77,7 +77,6 @@ To create the trimming test app:
* Create a separate console application project.
* Add a reference to the library.
-* Add calls to each API in the library.
* Modify the project similar to the project shown below using the following list:
### [.NET 6](#tab/net6)
@@ -101,11 +100,11 @@ To create the trimming test app:
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml" id="snippet_full":::
**Notes:**
-* In the preceding project file, when using .NET 8, replace `net7.0` with `net8.0`.
+* In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
* The `full` setting:
* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
@@ -140,11 +139,11 @@ The preceding steps produce warnings about code that may cause problems when use
Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) to indicate that the member references code that may be removed by the trimmer.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="17-18":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1":::
The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs" id="snippet_RequiresUnreferencedCode" highlight="3,9-10":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs" id="snippet_RequiresUnreferencedCode" highlight="9-10":::
Once you have propagated up the attribute all the way to public API, apps calling the library:
@@ -173,17 +172,23 @@ In this case, the trim analysis keeps public methods of , and
## Recommendations
-***Avoid*** reflection when possible.
+* ***Avoid*** reflection when possible. When using reflection, minimize reflection scope so that it's reachable only from a small part of the library.
+* Annotate code with `DynamicallyAccessedMembers` to statically express the trimming requirements statically when possible.
+* Consider reorganizing code to make it follow an analyzable pattern that can be annotated with `DynamicallyAccessedMembers`
+* When code is incompatible with trimming, annotate it with `RequiresUnreferencedCode` and propagate this annotation to callers until the relevant public APIs are annotated.
+* Avoid using code that uses reflection in a way not understood by the static analysis. For example, reflection in static constructors should be avoided. Using reflection in static constructors result in the warning propagating to all members of the class.
+* Avoid annotating virtual methods or interface methods. Annotating virtual or interface methods requires all overrides to have matching annotations.
+* If an API is mostly trim-incompatible, alternative coding approaches to the API may need to be considered. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. For example, see [How to use source generation in System.Text.Json](/dotnet/standard/serialization/system-text-json/source-generation)
+ non-trimmable patterns in places like static constructors. Static constructors result in the warning propagating to all members of the class.
+* Avoid using code that uses reflection in a way not understood by the static analysis. For example, reflection in static constructors should be avoided. Using reflection in static constructors result in the warning propagating to all members of the class.
* Avoid annotating virtual methods or interface methods. Annotating virtual or interface methods requires all overrides to have matching annotations.
-* In some cases, you're able to mechanically propagate warnings through the library code without issues. Sometimes this results in much of your public API being annotated with [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). Annotating with `[RequiresUnreferencedCode]` is the right thing to do if the library behaves in ways that can't be understood statically by the trim analysis.
-
+* When code is incompatible with trimming, propagate `RequiresUnreferencedCode` annotations up the call chain until the relevant public API is annotated. In some cases, adding attributes up the call chain resolves the warnings. Sometimes this results in much of the public API being annotated with [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute). Annotating with `[RequiresUnreferencedCode]` is the best approach if the library behaves in ways that can't be understood statically by the trim analysis.
* Code that uses patterns that can't be expressed in terms of the `DynamicallyAccessedMembers` attributes:
- * Consider reorganizing that code to make it follow an analyzable pattern. This also applies to code that only uses reflection to operate on statically known types.
-* If an API is mostly trim-incompatible, you may need to find other ways to write the API. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. For example, see [How to use source generation in System.Text.Json](/dotnet/standard/serialization/system-text-json/source-generation)
+ * Consider reorganizing that code to make it follow an analyzable pattern. This also applies to code that only uses reflection to operate on statically known types. For example, consider using a factory pattern instead of reflection.
+* If an API is mostly trim-incompatible, alternative coding approaches to the API may need to be considered. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. For example, see [How to use source generation in System.Text.Json](/dotnet/standard/serialization/system-text-json/source-generation)
+-->
## Resolve warnings for non-analyzable patterns
@@ -212,7 +217,7 @@ In the preceding code, the indexer property has been annotated so that the retur
If you're sure that the requirements are met, you can silence this warning by adding [`[UnconditionalSuppressMessage]`](xref:System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute) to the getter:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD2" highlight="1-9":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD2" highlight="9-10":::
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 982f367ec1c59..5078be7daed41 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -5,7 +5,6 @@
//
public class MyLibrary
{
- internal static Type type;
public static void MyMethod()
{
@@ -78,7 +77,7 @@ public class MyLibrary6
static void InitializeTypeField()
{
- MyLibrary.type = typeof(System.Tuple);
+ MyLibrary99.type = typeof(System.Tuple);
}
//
}
@@ -188,6 +187,12 @@ static void RunHelper()
helper.Invoke(null, null);
}
}
+
+public class MyLibrary99
+{
+ internal static Type type;
+}
+
//
public class MyLibrary22
{
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
index ef1c47ad7ad3e..b282411e74e87 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml
@@ -1,4 +1,5 @@
-
+
+
net8.0
@@ -13,3 +14,4 @@
+
From 08bb4a7eef9c517034981d944ae6dbaf7cd6bd48 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 8 Aug 2023 13:46:07 -1000
Subject: [PATCH 31/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index e16bb2d3ef6ad..cea00d6e6b409 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -221,7 +221,7 @@ If you're sure that the requirements are met, you can silence this warning by ad
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="9-10":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="":::
### DynamicDependency
From f77702f17b8cb5f1e948d7b75965cb99d930a3fb Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 8 Aug 2023 14:22:30 -1000
Subject: [PATCH 32/57] react to feedback
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 8 +++-----
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 6 ++++--
.../trimming/snippets/MyLibrary/MyLibrary.csproj | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index cea00d6e6b409..c991b05820ded 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -127,9 +127,7 @@ Follow the preceding pattern for multiple libraries. To see trim analysis warnin
* If the new version added non-understood reflection patterns.
* Even if there were no API changes.
-
-Introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`.
-`
+* Introducing trim analysis warnings is a breaking change when the library is used with `PublishTrimmed`.
## Resolve trim warnings
@@ -137,9 +135,9 @@ The preceding steps produce warnings about code that may cause problems when use
### RequiresUnreferencedCode
-Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) to indicate that the member references code that may be removed by the trimmer.
+Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) to indicate that the specified method requires dynamic access to code that is not referenced statically, for example, through .
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="12-13":::
The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 5078be7daed41..69f5cbb4a8006 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -201,12 +201,14 @@ public class MyLibrary22
[DynamicDependency("MyMethod(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
- [DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
+ [DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType",
+ "UnreferencedAssembly")]
[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
// generics
[DynamicDependency("GenericMethodName``1")]
[DynamicDependency("GenericMethod``2(``0,``1)")]
- [DynamicDependency("MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
+ [DynamicDependency(
+ "MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
[DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
[DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]
//
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
index 446a24cdc144f..8dce0bb68501a 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
@@ -3,7 +3,7 @@
net7.0
enable
- enable
+
\ No newline at end of file
From 9cce0c16e548300475339eef7a9aaa62dd9725b5 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 8 Aug 2023 17:21:31 -1000
Subject: [PATCH 33/57] react to feedback
---
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 69f5cbb4a8006..4ce1eb119a5be 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -201,8 +201,8 @@ public class MyLibrary22
[DynamicDependency("MyMethod(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
- [DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType",
- "UnreferencedAssembly")]
+ [DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType"
+ , "UnreferencedAssembly")]
[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
// generics
[DynamicDependency("GenericMethodName``1")]
From 19babff14ad15ddde6ec6418b35b79ccbf200da6 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 16 Aug 2023 13:46:29 -1000
Subject: [PATCH 34/57] Apply suggestions from code review
Co-authored-by: Vitek Karas <10670590+vitek-karas@users.noreply.github.com>
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index c991b05820ded..549ca99ae5699 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -66,7 +66,7 @@ When building and publishing a library:
* The implementations of the dependencies aren't available.
* The available reference assemblies don't have enough information for the trimmer to determine if they're compatible with trimming.
-Because of the dependency limitations, a self-contained test app which uses the library and its dependencies must be created. The test app executable includes all the information the trimmer requires to issue warning on trim incompatibilities in:
+Because of the dependency limitations, a self-contained test app which uses the library and its dependencies must be created. The test app includes all the information the trimmer requires to issue warning on trim incompatibilities in:
* The library code.
* The code that the library references from its dependencies.
@@ -81,11 +81,11 @@ To create the trimming test app:
### [.NET 6](#tab/net6)
-* Set the `TrimmerDefaultAction` property to `link` with `link` n a `` element.
+* Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root, ". A "root," assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root". A "root" assembly means the trimmer analyzes every call in the library and traverses all code paths that originate from that assembly.
### .csproj file
From 46f7dfa3208a4f0cfc6030fd8933cee617b8db77 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Fri, 18 Aug 2023 14:50:57 -1000
Subject: [PATCH 35/57] react to feedback
---
.../prepare-libraries-for-trimming.md | 31 +++++++++++++------
.../snippets/ConsoleApp1/ConsoleApp1.csproj | 17 ++++++++++
.../trimming/snippets/ConsoleApp1/Program.cs | 3 ++
.../trimming/snippets/MyLibrary/Class1.cs | 12 +++++++
4 files changed, 54 insertions(+), 9 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
create mode 100644 docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 549ca99ae5699..ffcb0d5dd7215 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -17,12 +17,14 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet) or later.
+---
+
## Enable library trim warnings
Trim warnings in a library can be found with either of the following methods:
* Enabling project-specific trimming using the `IsTrimmable` property.
-* Creating a trimming test app that uses all the APIs in the library, and enabling trimming for the test app.
+* Creating a trimming test app that uses the library and enabling trimming for the test app. It's not necessary to reference all the APIs in the library.
We recommend using both approaches. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a test app is more work, but shows all warnings.
@@ -33,11 +35,20 @@ We recommend using both approaches. Project-specific trimming is convenient and
To get the latest version of the analyzer with the most coverage, install the [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet) or later. Installing the .NET 8 SDK or later:
* Updates the tooling used to build an app or library and enable trim warnings.
-* Doesn't require targeting the .NET 7 or later runtime.
+* Provides significant trimming and analyzer improvements over previous .NET SDKs.
+* Does ***not*** require targeting the .NET 8 runtime. Libary authors can continue to target the .NET 6 runtime.
Set `true` in the project file.
-### [.NET 7+](#tab/net7plus)
+### [.NET 7](#tab/net7)
+
+To get the latest version of the analyzer with the most coverage, install the [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet) or later. Installing the .NET 8 SDK or later:
+
+* Updates the tooling used to build an app or library and enable trim warnings.
+* Provides significant trimming and analyzer improvements over previous .NET SDKs.
+* Does ***not*** require targeting the .NET 8 runtime. Libary authors can continue to target the .NET 7 runtime.
+
+### [.NET 8+](#tab/net8plus)
Set `true` in the project file.
@@ -71,7 +82,7 @@ Because of the dependency limitations, a self-contained test app which uses the
* The library code.
* The code that the library references from its dependencies.
-***Note:*** If the library has different behavior depending on the target framework, create a trimming test app for each of the target frameworks. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
+***Note:*** If the library has different behavior depending on the target framework, create a trimming test app for each of the target frameworks that support trimming. For example, if the library uses [conditional compilation](/dotnet/csharp/language-reference/preprocessor-directives#conditional-compilation) such as `#if NET7_0` to change behavior.
To create the trimming test app:
@@ -79,6 +90,8 @@ To create the trimming test app:
* Add a reference to the library.
* Modify the project similar to the project shown below using the following list:
+If library targets a TFM that is not trimmable, for example `net472` or `netstandard2.0`, there's no benefit to creating a trimming test app. Trimming only works for .NET 6 and later.
+
### [.NET 6](#tab/net6)
* Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
@@ -96,11 +109,11 @@ To create the trimming test app:
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
- * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root". A "root" assembly means the trimmer analyzes every call in the library, and traverses all code paths that originate from that assembly. `TrimmerRootAssembly` is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`. A project using `[AssemblyMetadata("IsTrimmable", "True")]` without `TrimmerRootAssembly` removes the unused library without analyzing it.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root". A "root" assembly means the trimmer analyzes every call in the library and traverses all code paths that originate from that assembly.
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj.xml" id="snippet_full":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj" higlight=":::
**Notes:**
@@ -141,7 +154,7 @@ Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System
The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs" id="snippet_RequiresUnreferencedCode" highlight="9-10":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs" id="snippet_RequiresUnreferencedCode" highlight="3":::
Once you have propagated up the attribute all the way to public API, apps calling the library:
@@ -154,7 +167,7 @@ Once you have propagated up the attribute all the way to public API, apps callin
In the preceding code, `UseMethods` is calling a reflection method that has a [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute) requirement. The requirement states that the type's public methods are available. Satisfy the requirement by adding the same requirement to the parameter of `UseMethods`.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_DAA2" highlight="3":::
Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the requirement. Similar to `[RequiresUnreferencedCode]`, once you have propagated up such warnings to public APIs, you're done.
@@ -219,7 +232,7 @@ If you're sure that the requirements are met, you can silence this warning by ad
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6,13-14":::
### DynamicDependency
diff --git a/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj b/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
new file mode 100644
index 0000000000000..5270bc7e25605
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
diff --git a/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs b/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs
new file mode 100644
index 0000000000000..14e0ff3525552
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs
@@ -0,0 +1,3 @@
+using System;
+
+Console.WriteLine(MyLib.MyClass.getMax(1, 2));
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 4ce1eb119a5be..5a2f8d12fd6d9 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -193,6 +193,18 @@ public class MyLibrary99
internal static Type type;
}
+public class MyLib
+{
+ public static class MyClass
+ {
+ public static int getMax(int a, int b)
+ {
+ return a > b ? a : b;
+ }
+ }
+
+}
+
//
public class MyLibrary22
{
From e91601228f08728f6650ef475cd2c44419a0e9e1 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Fri, 18 Aug 2023 17:16:31 -1000
Subject: [PATCH 36/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index ffcb0d5dd7215..9d0873c4fbcd4 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -113,7 +113,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj" higlight=":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj" highlight=":::
**Notes:**
From f6e29ec9ffe3bc71e4f3de76ec90b944c68a7454 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 21 Aug 2023 16:05:33 -1000
Subject: [PATCH 37/57] Apply suggestions from code review
Co-authored-by: Sven Boemer
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 9d0873c4fbcd4..b9b297036af7c 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -239,7 +239,7 @@ It's important to underline that it's only valid to suppress a warning if there
The [`[DynamicDependency]`](xref:System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute) attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes, which inform the trim analysis about the reflection behavior of the code, `[DynamicDependency]` only keeps other members. This can be used together with [`[UnconditionalSuppressMessage]`](xref:System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute) to fix some analysis warnings.
> [!WARNING]
-> Use `[DynamicDependency]` attribute only as a last resort when the other approaches aren't viable. It is preferable to express the reflection behavior using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) or [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute):
+> Use `[DynamicDependency]` attribute only as a last resort when the other approaches aren't viable. It is preferable to express the reflection behavior using [`[RequiresUnreferencedCode]`](xref:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute) or [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute).
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD4" highlight="1":::
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 5a2f8d12fd6d9..888f437cdb385 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -25,7 +25,7 @@ static void DynamicBehavior()
//
public class MyLibrary3
{
- static void UseMyMethods(Type type)
+ static void UseMethods(Type type)
{
// warning IL2070: MyLibrary.UseMethods(Type): 'this' argument does not satisfy
// 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
@@ -75,9 +75,9 @@ public class MyLibrary6
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static Type type;
- static void InitializeTypeField()
+ static void UseMethodsHelper()
{
- MyLibrary99.type = typeof(System.Tuple);
+ MyLibrary.type = typeof(System.Tuple);
}
//
}
From ef61a9b529b72d3d13a864ef8c99e6fd1c0bf735 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 21 Aug 2023 16:14:24 -1000
Subject: [PATCH 38/57] react to feedback
---
.../prepare-libraries-for-trimming.md | 2 +-
.../trimming/snippets/ConsoleApp1/Program.cs | 1 +
.../trimming/snippets/MyLibrary/Class1.cs | 14 ++------
.../trimming/snippets/MyLibrary/Class3.cs | 36 +++++++++++++++++++
4 files changed, 40 insertions(+), 13 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/MyLibrary/Class3.cs
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index b9b297036af7c..49b9e3fe1ce88 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -177,7 +177,7 @@ In the following example, an unknown [Type](/dotnet/api/system.type) flows into
Similarly, here the problem is that the field `type` is passed into a parameter with these requirements. It's fixed by adding [`[DynamicallyAccessedMembers]`](xref:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute) to the field. `[DynamicallyAccessedMembers]` warns about code that assigns incompatible values to the field. Sometimes this process continues until a public API is annotated, and other times it ends when a concrete type flows into a location with these requirements. For example:
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_UMH2" highlight="1":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class3.cs" id="snippet_UMH2" highlight="1":::
In this case, the trim analysis keeps public methods of , and produces further warnings.
diff --git a/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs b/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs
index 14e0ff3525552..b10ad00392688 100644
--- a/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs
+++ b/docs/core/deploying/trimming/snippets/ConsoleApp1/Program.cs
@@ -1,3 +1,4 @@
using System;
+using MyLibrary1;
Console.WriteLine(MyLib.MyClass.getMax(1, 2));
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 888f437cdb385..ba28aca28f4cb 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -2,6 +2,8 @@
using System.Reflection;
using System.Text;
+namespace MyLibrary1;
+
//
public class MyLibrary
{
@@ -69,18 +71,6 @@ static void UseMethodsHelper()
//
}
-public class MyLibrary6
-{
- //
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- static Type type;
-
- static void UseMethodsHelper()
- {
- MyLibrary.type = typeof(System.Tuple);
- }
- //
-}
public class MyLibrary7
{
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class3.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class3.cs
new file mode 100644
index 0000000000000..5df2c82c91084
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class3.cs
@@ -0,0 +1,36 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace MyLibrary3;
+class Class3
+{
+ //
+ public class MyLibrary
+ {
+ internal static Type type;
+
+ [RequiresUnreferencedCode("Calls DynamicBehavior.")]
+ public static void MyMethod()
+ {
+ DynamicBehavior();
+ }
+
+ [RequiresUnreferencedCode(
+ "DynamicBehavior is incompatible with trimming.")]
+ static void DynamicBehavior()
+ {
+ }
+ }
+
+ public class MyLibrary6
+ {
+ //
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ static Type type;
+
+ static void UseMethodsHelper()
+ {
+ MyLibrary.type = typeof(System.Tuple);
+ }
+ //
+ }
+}
From 7c74672c329900b75efac1d8ef575ea459a5dbb8 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 21 Aug 2023 16:23:56 -1000
Subject: [PATCH 39/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 49b9e3fe1ce88..3309b597d9e24 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -113,7 +113,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj" highlight=":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj" highlight="3":::
**Notes:**
From 77abc93bbc46999c1b276f6c6d6b60f6ceaa12a7 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 21 Aug 2023 16:49:53 -1000
Subject: [PATCH 40/57] react to feedback
---
.../trimming/prepare-libraries-for-trimming.md | 12 ++++++++++--
.../trimming/snippets/MyLibrary/Class1.cs | 4 ++--
.../snippets/MyLibrary/MyLibrary.csproj | 3 +--
.../snippets/MyTestLib6app/MyTestLib6app.csproj | 7 -------
.../snippets/MyTestLib6app/XMLFile1.xml | 17 +++++++++++++++++
5 files changed, 30 insertions(+), 13 deletions(-)
create mode 100644 docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 3309b597d9e24..7d06efd7c9b6b 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -102,10 +102,18 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml:::
-### [.NET 7+](#tab/net7plus)
+### [.NET 7](#tab/net7)
+
+* Add `true`.
+* Add a reference to the library project with ``.
+* Specify the library as a trimmer root assembly with ``.
+ * `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root". A "root" assembly means the trimmer analyzes every call in the library and traverses all code paths that originate from that assembly.
+
+### [.NET 8+](#tab/net8plus)
+
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index ba28aca28f4cb..0bf3979e4a3cc 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -7,10 +7,10 @@ namespace MyLibrary1;
//
public class MyLibrary
{
-
public static void MyMethod()
{
- // warning IL2026 : MyLibrary.MyMethod: Using 'MyLibrary.DynamicBehavior'
+ // warning IL2026 :
+ // MyLibrary.MyMethod: Using 'MyLibrary.DynamicBehavior'
// which has [RequiresUnreferencedCode] can break functionality
// when trimming app code.
DynamicBehavior();
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
index 8dce0bb68501a..ee93c65ef2ecf 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/MyLibrary.csproj
@@ -1,9 +1,8 @@
- net7.0
+ net8.0
enable
-
\ No newline at end of file
diff --git a/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj b/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj
index d0d70bd752cc6..b4a17d4f20234 100644
--- a/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj
+++ b/docs/core/deploying/trimming/snippets/MyTestLib6app/MyTestLib6app.csproj
@@ -2,17 +2,10 @@
Exe
-
net6.0
true
link
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml b/docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml
new file mode 100644
index 0000000000000..4e02e5d44ab0b
--- /dev/null
+++ b/docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net6.0
+ true
+
+ link
+
+
+
+
+
+
+
+
+
From f1a2fbc53ed127f34f803977f6f09674281b436d Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Mon, 21 Aug 2023 17:25:26 -1000
Subject: [PATCH 41/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 7d06efd7c9b6b..719ee9caf89de 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -102,7 +102,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml:::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/MyTestLib6app/XMLFile1.xml":::
### [.NET 7](#tab/net7)
From 0f60845d4e86701acde4ff5b488995e01f501bb6 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Tue, 22 Aug 2023 16:14:29 -1000
Subject: [PATCH 42/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 719ee9caf89de..8496c3fd1d499 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -15,7 +15,7 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
## Prerequisites
-[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet) or later.
+[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet) or later. We recommend installing the latest version of the .NET SDK to get the most up-to-date trimming warnings and analyzer coverage when targeting .NET 6 or NET 7.
---
From 9726db22c793bf487e432c780fc27a53f36eed87 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 11:47:31 -1000
Subject: [PATCH 43/57] react to feedback
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 8496c3fd1d499..922339bc1593f 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -15,9 +15,12 @@ The .NET SDK makes it possible to reduce the size of self-contained apps by [tri
## Prerequisites
-[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet) or later. We recommend installing the latest version of the .NET SDK to get the most up-to-date trimming warnings and analyzer coverage when targeting .NET 6 or NET 7.
+[.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet) or later.
----
+To get the most up-to-date trimming warnings and analyzer coverage:
+
+* Install and target the .NET 8 SDK or later.
+* When targeting .NET 6 or NET 7, install the .NET 8 SDK or later.
## Enable library trim warnings
@@ -48,6 +51,8 @@ To get the latest version of the analyzer with the most coverage, install the [.
* Provides significant trimming and analyzer improvements over previous .NET SDKs.
* Does ***not*** require targeting the .NET 8 runtime. Libary authors can continue to target the .NET 7 runtime.
+Set `true` in the project file.
+
### [.NET 8+](#tab/net8plus)
Set `true` in the project file.
From 24c58e5e144c68759f706f343ef81cbd0fa21e16 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 11:48:44 -1000
Subject: [PATCH 44/57] Apply suggestions from code review
Co-authored-by: Sven Boemer
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 922339bc1593f..7c78c81f4d7db 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -95,11 +95,11 @@ To create the trimming test app:
* Add a reference to the library.
* Modify the project similar to the project shown below using the following list:
-If library targets a TFM that is not trimmable, for example `net472` or `netstandard2.0`, there's no benefit to creating a trimming test app. Trimming only works for .NET 6 and later.
+If library targets a TFM that is not trimmable, for example `net472` or `netstandard2.0`, there's no benefit to creating a trimming test app. Trimming is only supported for .NET 6 and later.
### [.NET 6](#tab/net6)
-* Set the `TrimmerDefaultAction` property to `link` with `link` in a `` element.
+* Set `` to `link`.
* Add `true`.
* Add a reference to the library project with ``.
* Specify the library as a trimmer root assembly with ``.
@@ -165,7 +165,7 @@ Consider the following code that uses [`[RequiresUnreferencedCode]`](xref:System
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_1" highlight="12-13":::
-The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates up the call stack the warning so that callers of `MyMethod` get a warning instead:
+The preceding highlighted code indicates the library calls a method that has explicitly been annotated as incompatible with trimming. To get rid of the warning, consider whether `MyMethod` needs to call `DynamicBehavior`. If so, annotate the caller `MyMethod` with `[RequiresUnreferencedCode]` which propagates the warning so that callers of `MyMethod` get a warning instead:
:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class2.cs" id="snippet_RequiresUnreferencedCode" highlight="3":::
From 71b06172a96e718e75f71ff36612204eff1e97b5 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 11:52:35 -1000
Subject: [PATCH 45/57] react to feedback
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 7c78c81f4d7db..372f1bc5fd26c 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -116,6 +116,10 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
* Specify the library as a trimmer root assembly with ``.
* `TrimmerRootAssembly` ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root". A "root" assembly means the trimmer analyzes every call in the library and traverses all code paths that originate from that assembly.
+### .csproj file
+
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
+
### [.NET 8+](#tab/net8plus)
@@ -126,7 +130,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj" highlight="3":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
**Notes:**
From d6daddff8e42f50f1726d89b29696b9deec96b87 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:01:25 -1000
Subject: [PATCH 46/57] react to feedback
---
.../core/deploying/trimming/prepare-libraries-for-trimming.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 372f1bc5fd26c..6799eafa13632 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -130,7 +130,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
**Notes:**
@@ -249,7 +249,7 @@ If you're sure that the requirements are met, you can silence this warning by ad
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6,13-14":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3":::
### DynamicDependency
From 0c58ab6a24160062e1dd143567c56ff99b0d6e80 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:05:38 -1000
Subject: [PATCH 47/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 6799eafa13632..a1fb90f509cbe 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -130,7 +130,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
### .csproj file
-:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
+:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
**Notes:**
From 1830a37cc6614ea38e96d06e8c480963faa53308 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 13:26:51 -1000
Subject: [PATCH 48/57] react to feedback
---
.../trimming/prepare-libraries-for-trimming.md | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index a1fb90f509cbe..cbe9fa6b09336 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -120,6 +120,17 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
+**Notes:**
+
+* In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
+* The `full` setting:
+
+ * Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
+ * Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
+ * Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
+ * Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
+ * The preceding warnings can be issued for code that is unused by the library.
+
### [.NET 8+](#tab/net8plus)
@@ -134,7 +145,6 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
**Notes:**
-* In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
* The `full` setting:
* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
From b6c86c211c15bb660d7f5db3e8fac2cb3a8f46f1 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 13:35:39 -1000
Subject: [PATCH 49/57] react to feedback
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index cbe9fa6b09336..7644e42f6e801 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -123,9 +123,10 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
**Notes:**
* In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
-* The `full` setting:
+* `full` in the ` tag:
* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
+ * Is not shown in the preceding project file.
* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
* Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
@@ -145,9 +146,10 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
**Notes:**
-* The `full` setting:
+* `full` in the ` tag:
* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
+ * Is not shown in the preceding project file.
* Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
* Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
* Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
From 8436c117230aadc5f5b6e514a212a1c6497bf49c Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Wed, 23 Aug 2023 13:37:39 -1000
Subject: [PATCH 50/57] react to feedback
---
.../core/deploying/trimming/prepare-libraries-for-trimming.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 7644e42f6e801..d1c3a3ccfe439 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -123,7 +123,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
**Notes:**
* In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
-* `full` in the ` tag:
+* [`full`](/dotnet/core/compatibility/deployment/7.0/trim-all-assemblies#recommended-action) in the `` tag:
* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
* Is not shown in the preceding project file.
@@ -146,7 +146,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
**Notes:**
-* `full` in the ` tag:
+* [`full`](/dotnet/core/compatibility/deployment/7.0/trim-all-assemblies#recommended-action) in the `` tag:
* Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
* Is not shown in the preceding project file.
From b8bec1a145719988bbd4b5821bc478d7f820d32a Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 12:00:02 -1000
Subject: [PATCH 51/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index d1c3a3ccfe439..b4d632f524dd7 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -261,7 +261,7 @@ If you're sure that the requirements are met, you can silence this warning by ad
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6-7:::
### DynamicDependency
From 41202fb47a8ea32dbf4e268395bbb5572b716ae5 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 12:00:34 -1000
Subject: [PATCH 52/57] react to feedback
---
.../trimming/snippets/ConsoleApp1/ConsoleApp1.csproj | 1 -
.../deploying/trimming/snippets/MyLibrary/Class1.cs | 10 +++++-----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj b/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
index 5270bc7e25605..0a45beddd3aa6 100644
--- a/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
+++ b/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
@@ -4,7 +4,6 @@
Exe
net8.0
true
- true
true
true
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 0bf3979e4a3cc..c601fe38eecaf 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -146,12 +146,12 @@ class TypeWithConstructor
public class MyLibrary11
{
//
+ // Invalid justification and suppression: property being non-reflectively
+ // used by the app doesn't guarantee that the property will be available
+ // for reflection. Properties that are not visible targets of reflection
+ // are already optimized away with Native AOT trimming and may be
+ // optimized away for non-native deployment in the future as well.
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
- // Invalid justification and suppression: property being non-reflectively
- // used by the app doesn't guarantee that the property will be available
- // for reflection. Properties that are not visible targets of reflection
- // are already optimized away with Native AOT trimming and may be
- // optimized away for non-native deployment in the future as well.
Justification = "*INVALID* Only need to serialize properties that are used by"
+ "the app. *INVALID*")]
public string Serialize(object o)
From 59a533a29ea5a6061887b78d09fc32a6a79b3318 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 12:04:44 -1000
Subject: [PATCH 53/57] Apply suggestions from code review
Co-authored-by: Vitek Karas <10670590+vitek-karas@users.noreply.github.com>
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index b4d632f524dd7..a194f9e57ffa6 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -39,7 +39,7 @@ To get the latest version of the analyzer with the most coverage, install the [.
* Updates the tooling used to build an app or library and enable trim warnings.
* Provides significant trimming and analyzer improvements over previous .NET SDKs.
-* Does ***not*** require targeting the .NET 8 runtime. Libary authors can continue to target the .NET 6 runtime.
+* Does ***not*** require targeting the .NET 8 runtime. Library authors can continue to target the .NET 6 runtime.
Set `true` in the project file.
@@ -213,10 +213,10 @@ In this case, the trim analysis keeps public methods of , and
## Recommendations
* ***Avoid*** reflection when possible. When using reflection, minimize reflection scope so that it's reachable only from a small part of the library.
-* Annotate code with `DynamicallyAccessedMembers` to statically express the trimming requirements statically when possible.
+* Annotate code with `DynamicallyAccessedMembers` to statically express the trimming requirements when possible.
* Consider reorganizing code to make it follow an analyzable pattern that can be annotated with `DynamicallyAccessedMembers`
* When code is incompatible with trimming, annotate it with `RequiresUnreferencedCode` and propagate this annotation to callers until the relevant public APIs are annotated.
-* Avoid using code that uses reflection in a way not understood by the static analysis. For example, reflection in static constructors should be avoided. Using reflection in static constructors result in the warning propagating to all members of the class.
+* Avoid using code that uses reflection in a way not understood by the static analysis. For example, reflection in static constructors should be avoided. Using statically unanalyzable reflection in static constructors result in the warning propagating to all members of the class.
* Avoid annotating virtual methods or interface methods. Annotating virtual or interface methods requires all overrides to have matching annotations.
* If an API is mostly trim-incompatible, alternative coding approaches to the API may need to be considered. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. For example, see [How to use source generation in System.Text.Json](/dotnet/standard/serialization/system-text-json/source-generation)
From 96c45bc6bb33b8265734e4854353f80f1c0a5251 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 12:14:04 -1000
Subject: [PATCH 54/57] react to feedback
---
.../prepare-libraries-for-trimming.md | 24 +++----------------
.../snippets/ConsoleApp1/ConsoleApp1.csproj | 2 --
2 files changed, 3 insertions(+), 23 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index a194f9e57ffa6..99f837a8d7a31 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -120,17 +120,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
-**Notes:**
-
-* In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
-* [`full`](/dotnet/core/compatibility/deployment/7.0/trim-all-assemblies#recommended-action) in the `` tag:
-
- * Is the [default for .NET 7 and higher](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md).
- * Is not shown in the preceding project file.
- * Ensures that the trimmer only analyzes the parts of the library's dependencies that are used.
- * Tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option:
- * Warnings are issued originating from ***any*** part of a dependency that doesn't set `[AssemblyMetadata ("IsTrimmable", "Tue")]`
- * The preceding warnings can be issued for code that is unused by the library.
+**Note:** In the preceding project file, when using .NET 7, replace `net8.0` with `net7.0`.
### [.NET 8+](#tab/net8plus)
@@ -144,6 +134,7 @@ If library targets a TFM that is not trimmable, for example `net472` or `netstan
:::code language="xml" source="~/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj":::
+
---
@@ -220,16 +212,6 @@ In this case, the trim analysis keeps public methods of , and
* Avoid annotating virtual methods or interface methods. Annotating virtual or interface methods requires all overrides to have matching annotations.
* If an API is mostly trim-incompatible, alternative coding approaches to the API may need to be considered. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. For example, see [How to use source generation in System.Text.Json](/dotnet/standard/serialization/system-text-json/source-generation)
-
-
## Resolve warnings for non-analyzable patterns
It's better to resolve warnings by expressing the intent of your code using `[RequiresUnreferencedCode]` and `DynamicallyAccessedMembers` when possible. However, in some cases, you may be interested in enabling trimming of a library that uses patterns that can't be expressed with those attributes, or without refactoring existing code. This section describes some advanced ways to resolve trim analysis warnings.
diff --git a/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj b/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
index 0a45beddd3aa6..55fd487879304 100644
--- a/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
+++ b/docs/core/deploying/trimming/snippets/ConsoleApp1/ConsoleApp1.csproj
@@ -4,8 +4,6 @@
Exe
net8.0
true
- true
- true
From e765adbf5b596b10372a27db70fba62665e1999d Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 12:25:31 -1000
Subject: [PATCH 55/57] react to feedback
---
docs/core/deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 99f837a8d7a31..60bef734ff5eb 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -243,7 +243,7 @@ If you're sure that the requirements are met, you can silence this warning by ad
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6-7:::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6-7":::
### DynamicDependency
From 1608032acaac3f2686f822c0ad5364358da14181 Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 13:06:06 -1000
Subject: [PATCH 56/57] react to feedback
---
.../deploying/trimming/prepare-libraries-for-trimming.md | 2 +-
.../core/deploying/trimming/snippets/MyLibrary/Class1.cs | 9 ++++-----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
index 60bef734ff5eb..5f0d7f165bc2a 100644
--- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
+++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md
@@ -243,7 +243,7 @@ If you're sure that the requirements are met, you can silence this warning by ad
It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere.
-:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6-7":::
+:::code language="csharp" source="~/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs" id="snippet_AD3" highlight="6-8":::
### DynamicDependency
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index c601fe38eecaf..418fede802342 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -178,10 +178,6 @@ static void RunHelper()
}
}
-public class MyLibrary99
-{
- internal static Type type;
-}
public class MyLib
{
@@ -194,8 +190,11 @@ public static int getMax(int a, int b)
}
}
-
//
+public class MyLibrary99
+{
+ internal static Type type;
+}
public class MyLibrary22
{
//
From 45041e14cf02c4918b1fe639020edfd6d4106d1e Mon Sep 17 00:00:00 2001
From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com>
Date: Thu, 24 Aug 2023 13:07:42 -1000
Subject: [PATCH 57/57] react to feedback
---
docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
index 418fede802342..412cedaccc435 100644
--- a/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
+++ b/docs/core/deploying/trimming/snippets/MyLibrary/Class1.cs
@@ -176,9 +176,9 @@ static void RunHelper()
var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
helper.Invoke(null, null);
}
+ //
}
-
public class MyLib
{
public static class MyClass
@@ -190,7 +190,6 @@ public static int getMax(int a, int b)
}
}
-//
public class MyLibrary99
{
internal static Type type;