diff --git a/docs/ai/how-to/snippets/semantic-kernel/semantic-kernel.csproj b/docs/ai/how-to/snippets/semantic-kernel/semantic-kernel.csproj
index 9ecac6f44ee80..24535590c5090 100644
--- a/docs/ai/how-to/snippets/semantic-kernel/semantic-kernel.csproj
+++ b/docs/ai/how-to/snippets/semantic-kernel/semantic-kernel.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/docs/ai/tutorials/snippets/llm-eval/llm-eval.csproj b/docs/ai/tutorials/snippets/llm-eval/llm-eval.csproj
index 65e78083fc992..3d65abfba1929 100644
--- a/docs/ai/tutorials/snippets/llm-eval/llm-eval.csproj
+++ b/docs/ai/tutorials/snippets/llm-eval/llm-eval.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/docs/azure/includes/dotnet-all.md b/docs/azure/includes/dotnet-all.md
index a4f5d12e3c096..7b475c9cd42af 100644
--- a/docs/azure/includes/dotnet-all.md
+++ b/docs/azure/includes/dotnet-all.md
@@ -113,7 +113,7 @@
| Text Analytics | NuGet [5.3.0](https://www.nuget.org/packages/Azure.AI.TextAnalytics/5.3.0) | [docs](/dotnet/api/overview/azure/AI.TextAnalytics-readme) | GitHub [5.3.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.TextAnalytics_5.3.0/sdk/textanalytics/Azure.AI.TextAnalytics/) |
| Text Translation | NuGet [1.0.0](https://www.nuget.org/packages/Azure.AI.Translation.Text/1.0.0) | [docs](/dotnet/api/overview/azure/AI.Translation.Text-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.Translation.Text_1.0.0/sdk/translation/Azure.AI.Translation.Text/) |
| Time Series Insights | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.IoT.TimeSeriesInsights/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/IoT.TimeSeriesInsights-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.IoT.TimeSeriesInsights_1.0.0-beta.1/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/) |
-| TimeZone | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Maps.TimeZones/1.0.0-beta.1) | | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Maps.TimeZones_1.0.0-beta.1/sdk/maps/Azure.Maps.TimeZones/) |
+| TimeZone | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Maps.TimeZones/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Maps.TimeZones-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Maps.TimeZones_1.0.0-beta.1/sdk/maps/Azure.Maps.TimeZones/) |
| Vision Common | NuGet [0.15.1-beta.1](https://www.nuget.org/packages/Azure.AI.Vision.Common/0.15.1-beta.1) | | GitHub [0.15.1-beta.1](https://msasg.visualstudio.com/Skyman/_git/Carbon) |
| WCF Storage Queues | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Microsoft.WCF.Azure.StorageQueues/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Microsoft.WCF.Azure.StorageQueues-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.WCF.Azure.StorageQueues_1.0.0-beta.1/sdk/extension-wcf/Microsoft.WCF.Azure.StorageQueues/) |
| Web PubSub | NuGet [1.4.0](https://www.nuget.org/packages/Azure.Messaging.WebPubSub/1.4.0) | [docs](/dotnet/api/overview/azure/Messaging.WebPubSub-readme) | GitHub [1.4.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Messaging.WebPubSub_1.4.0/sdk/webpubsub/Azure.Messaging.WebPubSub/) |
diff --git a/docs/azure/includes/dotnet-new.md b/docs/azure/includes/dotnet-new.md
index ce8cd55b46ff3..013a808e88fca 100644
--- a/docs/azure/includes/dotnet-new.md
+++ b/docs/azure/includes/dotnet-new.md
@@ -117,7 +117,7 @@
| Text Analytics | NuGet [5.3.0](https://www.nuget.org/packages/Azure.AI.TextAnalytics/5.3.0) | [docs](/dotnet/api/overview/azure/AI.TextAnalytics-readme) | GitHub [5.3.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.TextAnalytics_5.3.0/sdk/textanalytics/Azure.AI.TextAnalytics/) |
| Text Translation | NuGet [1.0.0](https://www.nuget.org/packages/Azure.AI.Translation.Text/1.0.0) | [docs](/dotnet/api/overview/azure/AI.Translation.Text-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.Translation.Text_1.0.0/sdk/translation/Azure.AI.Translation.Text/) |
| Time Series Insights | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.IoT.TimeSeriesInsights/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/IoT.TimeSeriesInsights-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.IoT.TimeSeriesInsights_1.0.0-beta.1/sdk/timeseriesinsights/Azure.IoT.TimeSeriesInsights/) |
-| TimeZone | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Maps.TimeZones/1.0.0-beta.1) | | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Maps.TimeZones_1.0.0-beta.1/sdk/maps/Azure.Maps.TimeZones/) |
+| TimeZone | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Maps.TimeZones/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Maps.TimeZones-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Maps.TimeZones_1.0.0-beta.1/sdk/maps/Azure.Maps.TimeZones/) |
| Video Analyzer Edge | NuGet [1.0.0-beta.6](https://www.nuget.org/packages/Azure.Media.VideoAnalyzer.Edge/1.0.0-beta.6) | [docs](/dotnet/api/overview/azure/Media.VideoAnalyzer.Edge-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.6](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Media.VideoAnalyzer.Edge_1.0.0-beta.6/sdk/videoanalyzer/Azure.Media.VideoAnalyzer.Edge/) |
| Vision Common | NuGet [0.15.1-beta.1](https://www.nuget.org/packages/Azure.AI.Vision.Common/0.15.1-beta.1) | | GitHub [0.15.1-beta.1](https://msasg.visualstudio.com/Skyman/_git/Carbon) |
| WCF Storage Queues | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Microsoft.WCF.Azure.StorageQueues/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Microsoft.WCF.Azure.StorageQueues-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.WCF.Azure.StorageQueues_1.0.0-beta.1/sdk/extension-wcf/Microsoft.WCF.Azure.StorageQueues/) |
diff --git a/docs/azure/sdk/logging.md b/docs/azure/sdk/logging.md
index 4f1f410405f7e..34949b5ae3c67 100644
--- a/docs/azure/sdk/logging.md
+++ b/docs/azure/sdk/logging.md
@@ -91,7 +91,7 @@ using System.Diagnostics.Tracing;
using var listener = new AzureEventSourceListener((e, message) =>
{
// Only log messages from "Azure-Core" event source
- if (e.EventSource.Name == "Azure-Core")
+ if (string.Equals(e.EventSource.Name, "Azure-Core", StringComparison.Ordinal))
{
Console.WriteLine($"{DateTime.Now} {message}");
}
@@ -230,7 +230,7 @@ By default, logging of the aforementioned content is disabled. To enable logging
{
Diagnostics =
{
- IsLoggingContentEnabled = true,
+ IsLoggingContentEnabled = true
}
};
var client = new SecretClient(
diff --git a/docs/core/deploying/media/trim-self-contained/visual-studio-publish-edit-settings.png b/docs/core/deploying/media/trim-self-contained/visual-studio-publish-edit-settings.png
deleted file mode 100644
index 1046ad953977e..0000000000000
Binary files a/docs/core/deploying/media/trim-self-contained/visual-studio-publish-edit-settings.png and /dev/null differ
diff --git a/docs/core/deploying/media/trim-self-contained/visual-studio-publish-properties.png b/docs/core/deploying/media/trim-self-contained/visual-studio-publish-properties.png
deleted file mode 100644
index 37ab1e07ed21a..0000000000000
Binary files a/docs/core/deploying/media/trim-self-contained/visual-studio-publish-properties.png and /dev/null differ
diff --git a/docs/core/deploying/media/trim-self-contained/visual-studio-solution-explorer.png b/docs/core/deploying/media/trim-self-contained/visual-studio-solution-explorer.png
deleted file mode 100644
index 64eb0c7103b04..0000000000000
Binary files a/docs/core/deploying/media/trim-self-contained/visual-studio-solution-explorer.png and /dev/null differ
diff --git a/docs/core/diagnostics/media/aspire-starter.png b/docs/core/diagnostics/media/aspire-starter.png
deleted file mode 100644
index 8c2ed32474478..0000000000000
Binary files a/docs/core/diagnostics/media/aspire-starter.png and /dev/null differ
diff --git a/docs/core/project-sdk/msbuild-props.md b/docs/core/project-sdk/msbuild-props.md
index 2cb309e3a6b0e..95acc8b1ba0e8 100644
--- a/docs/core/project-sdk/msbuild-props.md
+++ b/docs/core/project-sdk/msbuild-props.md
@@ -1457,6 +1457,7 @@ The following MSBuild properties are documented in this section:
- [TestingPlatformShowTestsFailure](#testingplatformshowtestsfailure)
- [TestingExtensionsProfile](#testingextensionsprofile)
- [UseVSTest](#usevstest)
+- [MSTestAnalysisMode](#mstestanalysismode)
### IsTestProject
@@ -1561,6 +1562,10 @@ For more information, see [MSTest runner profile](../testing/unit-testing-mstest
Set the `UseVSTest` property to `true` to switch from the MSTest runner to the [VSTest](/visualstudio/test/vstest-console-options) runner when using the [MSTest project SDK](../testing/unit-testing-mstest-sdk.md).
+### MSTestAnalysisMode
+
+This property decides which analyzers are enabled at which severity. For more information, see [MSTest code analysis](../testing/mstest-analyzers/overview.md).
+
## Hosting-related properties
The following MSBuild properties are documented in this section:
diff --git a/docs/core/testing/mstest-analyzers/includes/disabled-in-all.md b/docs/core/testing/mstest-analyzers/includes/disabled-in-all.md
new file mode 100644
index 0000000000000..d9a4c2d784328
--- /dev/null
+++ b/docs/core/testing/mstest-analyzers/includes/disabled-in-all.md
@@ -0,0 +1,2 @@
+> [!NOTE]
+> This rule is opt-in. It's not enabled even when using `All`. For more information about `MSTestAnalysisMode`, see [MSTest code analysis](../overview.md).
diff --git a/docs/core/testing/mstest-analyzers/mstest0003.md b/docs/core/testing/mstest-analyzers/mstest0003.md
index e67ec0f9e2bf4..530269e70912e 100644
--- a/docs/core/testing/mstest-analyzers/mstest0003.md
+++ b/docs/core/testing/mstest-analyzers/mstest0003.md
@@ -16,16 +16,16 @@ dev_langs:
---
# MSTEST0003: Test methods should have valid layout
-| Property | Value |
-|-------------------------------------|----------------------------------------------------|
-| **Rule ID** | MSTEST0003 |
-| **Title** | Test methods should have valid layout |
-| **Category** | Usage |
-| **Fix is breaking or non-breaking** | Breaking |
-| **Enabled by default** | Yes |
-| **Default severity** | Warning |
-| **Introduced in version** | 3.2.0 |
-| **Is there a code fix** | Yes |
+| Property | Value |
+|-------------------------------------|------------------------------------------------------------------------------------------|
+| **Rule ID** | MSTEST0003 |
+| **Title** | Test methods should have valid layout |
+| **Category** | Usage |
+| **Fix is breaking or non-breaking** | Breaking |
+| **Enabled by default** | Yes |
+| **Default severity** | Warning (escalated to Error when setting `MSTestAnalysisMode` to `Recommended` or `All`) |
+| **Introduced in version** | 3.2.0 |
+| **Is there a code fix** | Yes |
## Cause
diff --git a/docs/core/testing/mstest-analyzers/mstest0015.md b/docs/core/testing/mstest-analyzers/mstest0015.md
index 494c5f9fd14a6..637be270497ac 100644
--- a/docs/core/testing/mstest-analyzers/mstest0015.md
+++ b/docs/core/testing/mstest-analyzers/mstest0015.md
@@ -40,6 +40,8 @@ Ensure that the test method isn't ignored.
Do not suppress a warning from this rule. If you ignore this rule, test method will be ignored.
+[!INCLUDE [disabled-in-all](includes/disabled-in-all.md)]
+
## Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
diff --git a/docs/core/testing/mstest-analyzers/mstest0019.md b/docs/core/testing/mstest-analyzers/mstest0019.md
index dc79e84eab0e2..2fb37605292e8 100644
--- a/docs/core/testing/mstest-analyzers/mstest0019.md
+++ b/docs/core/testing/mstest-analyzers/mstest0019.md
@@ -40,6 +40,8 @@ Replace the constructor call with a `[TestInitialize]` method.
You usually don't want to suppress warnings from this rule if you decided to opt-in for it.
+[!INCLUDE [disabled-in-all](includes/disabled-in-all.md)]
+
## Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
diff --git a/docs/core/testing/mstest-analyzers/mstest0020.md b/docs/core/testing/mstest-analyzers/mstest0020.md
index 677defcc7c33d..dfd0c91805d4b 100644
--- a/docs/core/testing/mstest-analyzers/mstest0020.md
+++ b/docs/core/testing/mstest-analyzers/mstest0020.md
@@ -40,6 +40,8 @@ Replace `[TestInitialize]` returning `void` by constructors.
You usually don't want to suppress warnings from this rule if you decided to opt-in for it.
+[!INCLUDE [disabled-in-all](includes/disabled-in-all.md)]
+
## Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
diff --git a/docs/core/testing/mstest-analyzers/mstest0021.md b/docs/core/testing/mstest-analyzers/mstest0021.md
index 4bf5f8c4b0093..5b77376285a4a 100644
--- a/docs/core/testing/mstest-analyzers/mstest0021.md
+++ b/docs/core/testing/mstest-analyzers/mstest0021.md
@@ -40,6 +40,8 @@ Replace `[TestCleanup]` method by `Dispose` or `DisposeAsync` pattern.
You usually don't want to suppress warnings from this rule if you decided to opt-in for it.
+[!INCLUDE [disabled-in-all](includes/disabled-in-all.md)]
+
## Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
diff --git a/docs/core/testing/mstest-analyzers/mstest0022.md b/docs/core/testing/mstest-analyzers/mstest0022.md
index 0a2febdc1d0f6..00df1ed07e2c8 100644
--- a/docs/core/testing/mstest-analyzers/mstest0022.md
+++ b/docs/core/testing/mstest-analyzers/mstest0022.md
@@ -40,6 +40,8 @@ Replace `Dispose` or `DisposeAsync` methods with `[TestCleanup]`.
You usually don't want to suppress warnings from this rule if you decided to opt-in for it.
+[!INCLUDE [disabled-in-all](includes/disabled-in-all.md)]
+
## Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
diff --git a/docs/core/testing/mstest-analyzers/overview.md b/docs/core/testing/mstest-analyzers/overview.md
index c9190b1417234..d8bd11d084fe9 100644
--- a/docs/core/testing/mstest-analyzers/overview.md
+++ b/docs/core/testing/mstest-analyzers/overview.md
@@ -15,6 +15,55 @@ ms.date: 12/20/2023
The rules are organized into categories such as performance usage...
+Starting with MSTest.TestFramework 3.7, the MSTest.Analyzers NuGet package is a dependency of the framework. For earlier versions, you need to use `MSTest` metapackage or add a package reference for `MSTest.Analyzers` explicitly.
+
+## MSTestAnalysisMode
+
+Starting with MSTest 3.8, an MSBuild property named `MSTestAnalysisMode` is available to determine which analyzers are enabled at which severity.
+
+> [!TIP]
+> To see which rules are enabled at which severity for each mode, you can navigate to the package of the version of interest in NuGet cache, locate the `globalconfigs` directory, and open the `.globalconfig` file corresponding to the analysis mode.
+> For more information on finding the NuGet cache directory, see [Managing the global packages, cache, and temp folders](/nuget/consume-packages/managing-the-global-packages-and-cache-folders). From that directory, locate `mstest.analyzers` directory, then the version (3.8 and higher), then `globalconfigs`.
+> Alternatively, you can download the NuGet package of the version of interest from `nuget.org` and view it in NuGet Package Explorer (Windows app), or view directly in the [web app version of NuGet Package Explorer](https://nuget.info/packages/MSTest.Analyzers/).
+
+The available values for this property:
+
+- [`None`](#none)
+- [`Default`](#default)
+- [`Recommended`](#recommended)
+- [`All`](#all)
+
+### `None`
+
+This value sets all analyzers to `none` severity, disabling all of them. You can then enable individual analyzers using `.editorconfig` or `.globalconfig` files.
+
+### `Default`
+
+This setting follows the default documented behavior for each rule.
+
+- Rules that are enabled by default will use their default severity.
+- Rules that are disabled by default will use `none` severity.
+
+> [!NOTE]
+> Rules that are enabled by default as warnings are violations that are expected to cause issues at run time.
+
+### `Recommended`
+
+This is the mode we expect most developers to use. Rules that are enabled by default with Info (`suggestion`) severity are escalated to warnings. Moreover, certain rules might be escalated to errors in both `Recommended` and `All` modes. For example, [MSTEST0003: Test methods should have valid layout](mstest0003.md) is escalated to error in `Recommended` and `All` modes.
+
+### `All`
+
+This mode is more aggressive than `Recommended`. All rules are enabled as warnings. As mentioned for `Recommended` mode, certain rules might be escalated to errors in both `Recommended` and `All` modes. For example, [MSTEST0003: Test methods should have valid layout](./mstest0003.md) is escalated to error in `Recommended` and `All` modes.
+
+> [!NOTE]
+> The following rules are completely opt-in and are not enabled in `Default`, `Recommended`, or `All` modes:
+>
+> - [MSTEST0015: Test method should not be ignored](mstest0015.md)
+> - [MSTEST0019: Prefer TestInitialize methods over constructors](mstest0019.md)
+> - [MSTEST0020: Prefer constructors over TestInitialize methods](mstest0020.md)
+> - [MSTEST0021: Prefer Dispose over TestCleanup methods](mstest0021.md)
+> - [MSTEST0022: Prefer TestCleanup over Dispose methods](mstest0022.md)
+
## Categories
### Design rules
diff --git a/docs/core/versions/selection.md b/docs/core/versions/selection.md
index 810511defdfbf..98a04662854e8 100644
--- a/docs/core/versions/selection.md
+++ b/docs/core/versions/selection.md
@@ -31,7 +31,7 @@ SDK commands include `dotnet new` and `dotnet run`. The .NET CLI must choose an
You can take advantage of the latest SDK features and improvements while targeting earlier .NET runtime versions. You can target different runtime versions of .NET using the same SDK tools.
-On rare occasions, you may need to use an earlier version of the SDK. You specify that version in a [*global.json* file](../tools/global-json.md). The "use latest" policy means you only use *global.json* to specify a .NET SDK version earlier than the latest installed version.
+In some circumstances, you may need to use a specific version of the SDK. You specify that version in a [*global.json* file](../tools/global-json.md).
*global.json* can be placed anywhere in the file hierarchy. You control which projects a given *global.json* applies to by its place in the file system. The .NET CLI searches for a *global.json* file iteratively navigating the path upward from the current working directory (which isn't necessarily the same as the project directory). The first *global.json* file found specifies the version used. If that SDK version is installed, that version is used. If the SDK specified in the *global.json* isn't found, the .NET CLI uses [matching rules](../tools/global-json.md#matching-rules) to select a compatible SDK, or fails if none is found.
@@ -53,6 +53,10 @@ The process for selecting an SDK version is:
For more information about SDK version selection, see the [Matching rules](../tools/global-json.md#matching-rules) and [rollForward](../tools/global-json.md#rollforward) sections of the [global.json overview](../tools/global-json.md) article.
+### Updating the SDK version
+
+It is important to update to the latest version of the SDK regularly to adopt the latest features, performance improvements, and bug fixes. To easily check for updates to the SDK, use the `dotnet sdk check` [command](../tools/dotnet-sdk-check.md). Additionally, if you select a specific version using *global.json*, consider a tool such as Dependabot to automatically update the pinned SDK version as new versions become available.
+
## Target framework monikers define build time APIs
You build your project against APIs defined in a **target framework moniker** (TFM). You specify the [target framework](../../standard/frameworks.md) in the project file. Set the `TargetFramework` element in your project file as shown in the following example:
@@ -175,5 +179,7 @@ The `RuntimeFrameworkVersion` element overrides the default version policy. For
## See also
+- [Dependabot supported ecosystems and repositories](https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories).
- [Download and install .NET](../install/index.yml).
+- [How to check that .NET is already installed](../install/how-to-detect-installed-versions.md).
- [How to remove the .NET Runtime and SDK](../install/remove-runtime-sdk-versions.md).
diff --git a/docs/csharp/fundamentals/coding-style/identifier-names.md b/docs/csharp/fundamentals/coding-style/identifier-names.md
index 740c1d1fd3b98..8f45b2518ad22 100644
--- a/docs/csharp/fundamentals/coding-style/identifier-names.md
+++ b/docs/csharp/fundamentals/coding-style/identifier-names.md
@@ -123,7 +123,7 @@ public record PhysicalAddress(
string ZipCode);
```
-For more information on positional records, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-definition).
+For more information on positional records, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition).
### Camel case
diff --git a/docs/csharp/fundamentals/functional/deconstruct.md b/docs/csharp/fundamentals/functional/deconstruct.md
index c43a9e990c396..273e8e6cb308b 100644
--- a/docs/csharp/fundamentals/functional/deconstruct.md
+++ b/docs/csharp/fundamentals/functional/deconstruct.md
@@ -102,7 +102,7 @@ Some system types provide the `Deconstruct` method as a convenience. For example
## `record` types
-When you declare a [record](../../language-reference/builtin-types/record.md) type by using two or more positional parameters, the compiler creates a `Deconstruct` method with an `out` parameter for each positional parameter in the `record` declaration. For more information, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-definition) and [Deconstructor behavior in derived records](../../language-reference/builtin-types/record.md#deconstructor-behavior-in-derived-records).
+When you declare a [record](../../language-reference/builtin-types/record.md) type by using two or more positional parameters, the compiler creates a `Deconstruct` method with an `out` parameter for each positional parameter in the `record` declaration. For more information, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) and [Deconstructor behavior in derived records](../../language-reference/builtin-types/record.md#deconstructor-behavior-in-derived-records).
## See also
diff --git a/docs/csharp/fundamentals/types/records.md b/docs/csharp/fundamentals/types/records.md
index 15a9f6d1ca8d9..80a15b191ede2 100644
--- a/docs/csharp/fundamentals/types/records.md
+++ b/docs/csharp/fundamentals/types/records.md
@@ -33,7 +33,7 @@ Immutability isn't appropriate for all data scenarios. [Entity Framework Core](/
The same syntax that [declares](classes.md#declaring-classes) and [instantiates](classes.md#creating-objects) classes or structs can be used with records. Just substitute the `class` keyword with the `record`, or use `record struct` instead of `struct`. Likewise, the same syntax for expressing inheritance relationships is supported by record classes. Records differ from classes in the following ways:
-* You can use [positional parameters](../../language-reference/builtin-types/record.md#positional-syntax-for-property-definition) in a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) to create and instantiate a type with immutable properties.
+* You can use [positional parameters](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) in a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) to create and instantiate a type with immutable properties.
* The same methods and operators that indicate reference equality or inequality in classes (such as and `==`), indicate [value equality or inequality](../../language-reference/builtin-types/record.md#value-equality) in records.
* You can use a [`with` expression](../../language-reference/builtin-types/record.md#nondestructive-mutation) to create a copy of an immutable object with new values in selected properties.
* A record's `ToString` method creates a formatted string that shows an object's type name and the names and values of all its public properties.
diff --git a/docs/csharp/language-reference/attributes/general.md b/docs/csharp/language-reference/attributes/general.md
index 9821ef126b1b7..ac263c67eac6d 100644
--- a/docs/csharp/language-reference/attributes/general.md
+++ b/docs/csharp/language-reference/attributes/general.md
@@ -129,7 +129,7 @@ If is `false`, then derived clas
In this case, `NonInheritedAttribute` isn't applied to `DClass` via inheritance.
-You can also use these keywords to specify where an attribute should be applied. For example, you can use the `field:` specifier to add an attribute to the backing field of an [automatically implemented property](../../programming-guide/classes-and-structs/properties.md#automatically-implemented-properties). Or you can use the `field:`, `property:` or `param:` specifier to apply an attribute to any of the elements generated from a positional record. For an example, see [Positional syntax for property definition](../builtin-types/record.md#positional-syntax-for-property-definition).
+You can also use these keywords to specify where an attribute should be applied. For example, you can use the `field:` specifier to add an attribute to the backing field of an [automatically implemented property](../../programming-guide/classes-and-structs/properties.md#automatically-implemented-properties). Or you can use the `field:`, `property:` or `param:` specifier to apply an attribute to any of the elements generated from a positional record. For an example, see [Positional syntax for property definition](../builtin-types/record.md#positional-syntax-for-property-and-field-definition).
## `AsyncMethodBuilder` attribute
diff --git a/docs/csharp/language-reference/builtin-types/record.md b/docs/csharp/language-reference/builtin-types/record.md
index 4c395209b61eb..2995ba37b741f 100644
--- a/docs/csharp/language-reference/builtin-types/record.md
+++ b/docs/csharp/language-reference/builtin-types/record.md
@@ -1,7 +1,7 @@
---
title: "Records"
-description: Learn about the record type in C#
-ms.date: 11/22/2023
+description: Learn about the record modifier for class and struct types in C#. Records provide standard support for value based equality on instances of record types.
+ms.date: 02/05/2025
f1_keywords:
- "record_CSharpKeyword"
helpviewer_keywords:
@@ -35,7 +35,7 @@ Record structs can be mutable as well, both positional record structs and record
While records can be mutable, they're primarily intended for supporting immutable data models. The record type offers the following features:
-* [Concise syntax for creating a reference type with immutable properties](#positional-syntax-for-property-definition)
+* [Concise syntax for creating a reference type with immutable properties](#positional-syntax-for-property-and-field-definition)
* Built-in behavior useful for a data-centric reference type:
* [Value equality](#value-equality)
* [Concise syntax for nondestructive mutation](#nondestructive-mutation)
@@ -49,9 +49,9 @@ The preceding examples show some distinctions between records that are reference
The remainder of this article discusses both `record class` and `record struct` types. The differences are detailed in each section. You should decide between a `record class` and a `record struct` similar to deciding between a `class` and a `struct`. The term *record* is used to describe behavior that applies to all record types. Either `record struct` or `record class` is used to describe behavior that applies to only struct or class types, respectively.
-## Positional syntax for property definition
+## Positional syntax for property and field definition
-You can use positional parameters to declare properties of a record and to initialize the property values when you create an instance:
+You can use positional parameters to declare properties of a record or to initialize property or field values. The following example creates a record with two positional properties:
:::code language="csharp" source="snippets/shared/RecordType.cs" id="InstantiatePositional":::
@@ -70,19 +70,23 @@ You might want to add attributes to any of these elements the compiler creates f
The preceding example also shows how to create XML documentation comments for the record. You can add the `` tag to add documentation for the primary constructor's parameters.
-If the generated automatically implemented property definition isn't what you want, you can define your own property of the same name. For example, you might want to change accessibility or mutability, or provide an implementation for either the `get` or `set` accessor. If you declare the property in your source, you must initialize it from the positional parameter of the record. If your property is an automatically implemented property, you must initialize the property. If you add a backing field in your source, you must initialize the backing field. The generated deconstructor uses your property definition. For instance, the following example declares the `FirstName` and `LastName` properties of a positional record `public`, but restricts the `Id` positional parameter to `internal`. You can use this syntax for records and record struct types.
+If the generated automatically implemented property definition isn't what you want, you can define your own property or field of the same name. For example, you might want to change accessibility or mutability, or provide an implementation for either the `get` or `set` accessor. If you declare the member in your source, you must initialize it from the positional parameter of the record. If your property is an automatically implemented property, you must initialize the property. If you add a backing field in your source, you must initialize the backing field. The generated deconstructor uses your property or field definition. For instance, the following example declares the `FirstName` and `LastName` properties of a positional record `public`, but restricts the `Id` positional parameter to `internal`. You can use this syntax for records and record struct types.
:::code language="csharp" source="snippets/shared/RecordType.cs" id="PositionalWithManualProperty":::
+If you want to create a field instead of a property, assign the positional parameter to a field, as shown in the following example:
+
+:::code language="csharp" source="snippets/shared/RecordType.cs" id="PositionalWithManualField":::
+
A record type doesn't have to declare any positional properties. You can declare a record without any positional properties, and you can declare other fields and properties, as in the following example:
:::code language="csharp" source="snippets/shared/RecordType.cs" id="MixedSyntax":::
-If you define properties by using standard property syntax but omit the access modifier, the properties are implicitly `private`.
+Properties that the compiler generates from positional parameters are `public`. You declare the access modifiers on any properties you explicitly declare.
## Immutability
-A *positional record* and a *positional readonly record struct* declare init-only properties. A *positional record struct* declares read-write properties. You can override either of those defaults, as shown in the previous section.
+A *positional record class* and a *positional readonly record struct* declare init-only properties. A *positional record struct* declares read-write properties. You can override either of those defaults, as shown in the previous section.
Immutability can be useful when you need a data-centric type to be thread-safe or you're depending on a hash code remaining the same in a hash table. Immutability isn't appropriate for all data scenarios, however. [Entity Framework Core](/ef/core/), for example, doesn't support updating with immutable entity types.
@@ -211,7 +215,7 @@ Here's an example of code that replaces the synthesized `PrintMembers` methods,
:::code language="csharp" source="snippets/shared/RecordType.cs" id="PrintMembersImplementation":::
> [!NOTE]
-> The compiler will synthesize `PrintMembers` in derived records even when a base record has sealed the `ToString` method. You can also create your own implementation of `PrintMembers`.
+> The compiler synthesizes `PrintMembers` in derived records even when a base record sealed the `ToString` method. You can also create your own implementation of `PrintMembers`.
### Deconstructor behavior in derived records
diff --git a/docs/csharp/language-reference/builtin-types/snippets/shared/RecordType.cs b/docs/csharp/language-reference/builtin-types/snippets/shared/RecordType.cs
index 245edb987fcc0..e01198e5a8b4b 100644
--- a/docs/csharp/language-reference/builtin-types/snippets/shared/RecordType.cs
+++ b/docs/csharp/language-reference/builtin-types/snippets/shared/RecordType.cs
@@ -145,6 +145,26 @@ public static void Main()
}
}
+ namespace positionalwithmanualfield
+ {
+ public static class Example
+ {
+ //
+ public record Person(string FirstName, string LastName, string Id)
+ {
+ internal readonly string Id = Id; // this.Id set to parameter Id
+ }
+
+ public static void Main()
+ {
+ Person person = new("Nancy", "Davolio", "12345");
+ Console.WriteLine(person.FirstName); //output: Nancy
+
+ }
+ //
+ }
+ }
+
namespace shallowimmutability
{
public static class Example
diff --git a/docs/csharp/language-reference/keywords/required.md b/docs/csharp/language-reference/keywords/required.md
index 78c2fd29ca0c2..105465d33bdea 100644
--- a/docs/csharp/language-reference/keywords/required.md
+++ b/docs/csharp/language-reference/keywords/required.md
@@ -19,7 +19,7 @@ The `required` modifier indicates that the *field* or *property* it's applied to
- A type with any `required` members may not be used as a type argument when the type parameter includes the `new()` constraint. The compiler can't enforce that all required members are initialized in the generic code.
- The `required` modifier isn't allowed on the declaration for positional parameters on a record. You can add an explicit declaration for a positional property that does include the `required` modifier.
-Some types, such as [positional records](../builtin-types/record.md#positional-syntax-for-property-definition), use a primary constructor to initialize positional properties. If any of those properties include the `required` modifier, the primary constructor adds the [`SetsRequiredMembers`](../attributes/general.md#setsrequiredmembers-attribute) attribute. This indicates that the primary constructor initializes all required members. You can write your own constructor with the attribute. However, the compiler doesn't verify that these constructors do initialize all required members. Rather, the attribute asserts to the compiler that the constructor does initialize all required members. The `SetsRequiredMembers` attribute adds these rules to constructors:
+Some types, such as [positional records](../builtin-types/record.md#positional-syntax-for-property-and-field-definition), use a primary constructor to initialize positional properties. If any of those properties include the `required` modifier, the primary constructor adds the [`SetsRequiredMembers`](../attributes/general.md#setsrequiredmembers-attribute) attribute. This indicates that the primary constructor initializes all required members. You can write your own constructor with the attribute. However, the compiler doesn't verify that these constructors do initialize all required members. Rather, the attribute asserts to the compiler that the constructor does initialize all required members. The `SetsRequiredMembers` attribute adds these rules to constructors:
- A constructor that chains to another constructor annotated with the `SetsRequiredMembers` attribute, either `this()`, or `base()`, must also include the `SetsRequiredMembers` attribute. That ensures that callers can correctly use all appropriate constructors.
- Copy constructors generated for `record` types have the `SetsRequiredMembers` attribute applied if any of the members are `required`.
diff --git a/docs/csharp/language-reference/operators/deconstruction.md b/docs/csharp/language-reference/operators/deconstruction.md
index de77c4f3c86aa..61e6554c6ade3 100644
--- a/docs/csharp/language-reference/operators/deconstruction.md
+++ b/docs/csharp/language-reference/operators/deconstruction.md
@@ -23,7 +23,7 @@ In the preceding example, the `Y` and `label` members are discarded. You can spe
## Record deconstruction
-[Record](../builtin-types/record.md) types that have a [primary constructor](../builtin-types/record.md#positional-syntax-for-property-definition) support deconstruction for positional parameters. The compiler synthesizes a `Deconstruct` method that extracts the properties synthesized from positional parameters in the primary constructor. The compiler-synthesized `Deconstruction` method doesn't extract properties declared as properties in the record type.
+[Record](../builtin-types/record.md) types that have a [primary constructor](../builtin-types/record.md#positional-syntax-for-property-and-field-definition) support deconstruction for positional parameters. The compiler synthesizes a `Deconstruct` method that extracts the properties synthesized from positional parameters in the primary constructor. The compiler-synthesized `Deconstruction` method doesn't extract properties declared as properties in the record type.
The `record` shown in the following code declares two positional properties, `SquareFeet` and `Address`, along with another property, `RealtorNotes`:
diff --git a/docs/csharp/language-reference/operators/patterns.md b/docs/csharp/language-reference/operators/patterns.md
index a385c5d686fe4..7d578c523fad4 100644
--- a/docs/csharp/language-reference/operators/patterns.md
+++ b/docs/csharp/language-reference/operators/patterns.md
@@ -226,7 +226,7 @@ You can also extend a positional pattern in any of the following ways:
:::code language="csharp" source="snippets/patterns/PositionalPattern.cs" id="WithTypeCheck":::
- The preceding example uses [positional records](../builtin-types/record.md#positional-syntax-for-property-definition) that implicitly provide the `Deconstruct` method.
+ The preceding example uses [positional records](../builtin-types/record.md#positional-syntax-for-property-and-field-definition) that implicitly provide the `Deconstruct` method.
- Use a [property pattern](#property-pattern) within a positional pattern, as the following example shows:
diff --git a/docs/framework/ui-automation/implementing-the-ui-automation-selectionitem-control-pattern.md b/docs/framework/ui-automation/implementing-the-ui-automation-selectionitem-control-pattern.md
index 87ac7e832fff8..d758c6a312ea5 100644
--- a/docs/framework/ui-automation/implementing-the-ui-automation-selectionitem-control-pattern.md
+++ b/docs/framework/ui-automation/implementing-the-ui-automation-selectionitem-control-pattern.md
@@ -29,16 +29,21 @@ ms.assetid: 76b0949a-5b23-4cfc-84cc-154f713e2e12
## Required Members for ISelectionItemProvider
- The following properties, methods, and events are required for implementing .
+The following properties, methods, and events are required for implementing .
-|Required members|Member type|Notes|
+| Required members | Member type | Notes |
|----------------------|-----------------|-----------|
-||Property|None|
-||Property|None|
-||Method|None|
-||Event|Raised when a selection in a container has changed significantly and requires sending more and events than the constant permits.|
-
-- If the result of a , an , or a is a single selected item, an should be raised; otherwise send / as appropriate.
+| | Property | None |
+| | Property | None |
+| | Method | None |
+| | Method | None |
+| | Method | None |
+| | Event | Raised when a selection change results in a single selected item. |
+| | Event | Raised when an item is added to a multi-selection container. |
+| | Event | Raised when an item is removed from a multi-selection container. |
+| | Event | Raised when a selection in a container has changed significantly and requires sending more and events than the constant permits. |
+
+- If a , , or operation results in a single selected item, raise ; otherwise, raise or as appropriate.
diff --git a/docs/fundamentals/networking/telemetry/media/prometheus-active-requests.png b/docs/fundamentals/networking/telemetry/media/prometheus-active-requests.png
deleted file mode 100644
index 3af89ed066f8b..0000000000000
Binary files a/docs/fundamentals/networking/telemetry/media/prometheus-active-requests.png and /dev/null differ
diff --git a/docs/fundamentals/networking/telemetry/media/prometheus-search.png b/docs/fundamentals/networking/telemetry/media/prometheus-search.png
deleted file mode 100644
index 058e31b4640cf..0000000000000
Binary files a/docs/fundamentals/networking/telemetry/media/prometheus-search.png and /dev/null differ
diff --git a/docs/standard/native-interop/custom-marshalling-source-generation.md b/docs/standard/native-interop/custom-marshalling-source-generation.md
index 04fdd4bfd408c..aece9c32ef2f4 100644
--- a/docs/standard/native-interop/custom-marshalling-source-generation.md
+++ b/docs/standard/native-interop/custom-marshalling-source-generation.md
@@ -124,7 +124,7 @@ The `ListMarshaller` in the example is a stateless collection marshaller that im
```csharp
[LibraryImport("nativelib")]
[return: MarshalUsing(typeof(ListMarshaller<,>), CountElementName = "numValues")]
-internal static partial void ConvertList(
+internal static partial List ConvertList(
[MarshalUsing(typeof(ListMarshaller<,>))] List list,
out int numValues);
```
diff --git a/docs/standard/serialization/binaryformatter-migration-guide/read-nrbf-payloads.md b/docs/standard/serialization/binaryformatter-migration-guide/read-nrbf-payloads.md
index 581a219d4682a..f21049a6d1589 100644
--- a/docs/standard/serialization/binaryformatter-migration-guide/read-nrbf-payloads.md
+++ b/docs/standard/serialization/binaryformatter-migration-guide/read-nrbf-payloads.md
@@ -18,6 +18,9 @@ helpviewer_keywords:
As part of .NET 9, a new [NrbfDecoder] class was introduced to decode NRBF payloads without performing _deserialization_ of the payload. This API can safely be used to decode trusted or untrusted payloads without any of the risks that [BinaryFormatter] deserialization carries. However, [NrbfDecoder] merely decodes the data into structures an application can further process. Care must be taken when using [NrbfDecoder] to safely load the data into the appropriate instances.
+> [!CAUTION]
+> [NrbfDecoder] is _an_ implementation of an NRBF reader, but its behaviors don't strictly follow [BinaryFormatter]'s implementation. Thus you shouldn't use the output of [NrbfDecoder] to determine whether a call to [BinaryFormatter] would be safe.
+
You can think of as being the equivalent of using a JSON/XML reader without the deserializer.
## NrbfDecoder
@@ -33,7 +36,8 @@ You can think of as being the equivalent
- Use collision-resistant randomized hashing to store records referenced by other records (to avoid running out of memory for dictionary backed by an array whose size depends on the number of hash-code collisions).
- Only primitive types can be instantiated in an implicit way. Arrays can be instantiated on demand. Other types are never instantiated.
-When using [NrbfDecoder], it is important not to reintroduce those capabilities in general-purpose code as doing so would negate these safeguards.
+> [!CAUTION]
+> When using [NrbfDecoder], it's important not to reintroduce those capabilities in general-purpose code, as doing so would negate these safeguards.
### Deserialize a closed set of types
@@ -82,17 +86,38 @@ internal static T LoadFromFile(string path)
The NRBF payload consists of serialization records that represent the serialized objects and their metadata. To read the whole payload and get the root object, you need to call the method.
-The method returns a instance. is an abstract class that represents the serialization record and provides three self-describing properties: , , and . It exposes one method, , which compares the type name read from the payload (and exposed via property) against the specified type. This method ignores assembly names, so users don't need to worry about type forwarding and assembly versioning. It also does not consider member names or their types (because getting this information would require type loading).
+The method returns a instance. is an abstract class that represents the serialization record and provides three self-describing properties: , , and .
+
+> [!NOTE]
+> An attacker could create a payload with cycles (example: class or an array of objects with a reference to itself). The returns an instance of which implements and amongst other things, it can be used to detect cycles in decoded records.
+
+ exposes one method, , which compares the type name read from the payload (and exposed via property) against the specified type. This method ignores assembly names, so users don't need to worry about type forwarding and assembly versioning. It also does not consider member names or their types (because getting this information would require type loading).
```csharp
using System.Formats.Nrbf;
-static T Pseudocode(Stream payload)
+static Animal Pseudocode(Stream payload)
{
SerializationRecord record = NrbfDecoder.Read(payload);
- if (!record.TypeNameMatches(typeof(T))
+ if (record.TypeNameMatches(typeof(Cat)) && record is ClassRecord catRecord)
+ {
+ return new Cat()
+ {
+ Name = catRecord.GetString("Name"),
+ WorshippersCount = catRecord.GetInt32("WorshippersCount")
+ };
+ }
+ else if (record.TypeNameMatches(typeof(Dog)) && record is ClassRecord dogRecord)
{
- throw new Exception($"Expected the record to match type name `{typeof(T).AssemblyQualifiedName}`, but got `{record.TypeName.AssemblyQualifiedName}`."
+ return new Dog()
+ {
+ Name = dogRecord.GetString("Name"),
+ FriendsCount = dogRecord.GetInt32("FriendsCount")
+ };
+ }
+ else
+ {
+ throw new Exception($"Unexpected record: `{record.TypeName.AssemblyQualifiedName}`.");
}
}
```
@@ -104,7 +129,7 @@ There are more than a dozen different serialization [record types](/openspecs/wi
- derives from the non-generic , which also exposes a property. But on the base class, the value is returned as `object` (which introduces boxing for value types).
- : describes all `class` and `struct` besides the aforementioned primitive types.
- : describes all array records, including jagged and multi-dimensional arrays.
-- : describes single-dimensional, zero-indexed array records, where `T` can be either a primitive type or a .
+- : describes single-dimensional, zero-indexed array records, where `T` can be either a primitive type or a .
```csharp
SerializationRecord rootObject = NrbfDecoder.Decode(payload); // payload is a Stream
@@ -134,7 +159,8 @@ The API it provides:
- property that gets the names of serialized members.
- method that checks if member of given name was present in the payload. It was designed for handling versioning scenarios where given member could have been renamed.
- A set of dedicated methods for retrieving primitive values of the provided member name: , , , , , , , , , , , , , , , and .
-- and methods to retrieve instance of given record types.
+- retrieves an instance of [ClassRecord]. In case of a cycle, it's the same instance of the current [ClassRecord] with the same .
+- retrieves an instance of [ArrayRecord].
- to retrieve any serialization record and to retrieve any serialization record or a raw primitive value.
The following code snippet shows in action:
@@ -157,22 +183,30 @@ Sample output = new()
Text = rootRecord.GetString(nameof(Sample.Text)),
// using dedicated method to read an array of bytes
ArrayOfBytes = ((SZArrayRecord)rootRecord.GetArrayRecord(nameof(Sample.ArrayOfBytes))).GetArray(),
- // using GetClassRecord to read a class record
- ClassInstance = new()
+};
+
+// using GetClassRecord to read a class record
+ClassRecord? referenced = rootRecord.GetClassRecord(nameof(Sample.ClassInstance));
+if (referenced is not null)
+{
+ if (referenced.Id.Equals(rootRecord.Id))
{
- Text = rootRecord
- .GetClassRecord(nameof(Sample.ClassInstance))!
- .GetString(nameof(Sample.Text))
+ throw new Exception("Unexpected cycle detected!");
}
-};
+
+ output.ClassInstance = new()
+ {
+ Text = referenced.GetString(nameof(Sample.Text))
+ };
+}
```
#### ArrayRecord
defines the core behavior for NRBF array records and provides a base for derived classes. It provides two properties:
-- which gets the rank of the array.
-- which get a buffer of integers that represent the number of elements in every dimension.
+- , which gets the rank of the array.
+- , which gets a buffer of integers that represent the number of elements in every dimension. It's recommended to **check the total length of the provided array record** before calling .
It also provides one method: . When used for the first time, it allocates an array and fills it with the data provided in the serialized records (in case of the natively supported primitive types like `string` or `int`) or the serialized records themselves (in case of arrays of complex types).
@@ -180,11 +214,18 @@ It also provides one method: . W
```csharp
ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(stream);
+if (arrayRecord.Rank != 2 || arrayRecord.Lengths[0] * arrayRecord.Lengths[1] > 10_000)
+{
+ throw new Exception("The array had unexpected rank or length!");
+}
int[,] array2d = (int[,])arrayRecord.GetArray(typeof(int[,]));
```
If there is a type mismatch (example: the attacker has provided a payload with an array of two billion strings), the method throws .
+> [!CAUTION]
+> Unfortunately, the NRBF format makes it easy for an attacker to compress a large number of null array items. That's why it's recommended to always check the total length of the array before calling . Moreover, accepts an optional `allowNulls` Boolean argument, which, when set to `false`, will throw for nulls.
+
[NrbfDecoder] does not load or instantiate any custom types, so in case of arrays of complex types, it returns an array of .
```csharp
@@ -195,14 +236,18 @@ public class ComplexType3D
}
ArrayRecord arrayRecord = (ArrayRecord)NrbfDecoder.Decode(payload);
-SerializationRecord[] records = (SerializationRecord[])arrayRecord.GetArray(expectedArrayType: typeof(ComplexType3D[]));
+if (arrayRecord.Rank != 1 || arrayRecord.Lengths[0] > 10_000)
+{
+ throw new Exception("The array had unexpected rank or length!");
+}
+
+SerializationRecord[] records = (SerializationRecord[])arrayRecord.GetArray(expectedArrayType: typeof(ComplexType3D[]), allowNulls: false);
ComplexType3D[] output = records.OfType().Select(classRecord => new ComplexType3D()
{
I = classRecord.GetInt32(nameof(ComplexType3D.I)),
J = classRecord.GetInt32(nameof(ComplexType3D.J)),
K = classRecord.GetInt32(nameof(ComplexType3D.K)),
}).ToArray();
-
```
.NET Framework supported non-zero indexed arrays within NRBF payloads, but this support was never ported to .NET (Core). [NrbfDecoder] therefore does not support decoding non-zero indexed arrays.
diff --git a/docs/standard/serialization/system-text-json/immutability.md b/docs/standard/serialization/system-text-json/immutability.md
index 2745d1a617433..480aa6b16981f 100644
--- a/docs/standard/serialization/system-text-json/immutability.md
+++ b/docs/standard/serialization/system-text-json/immutability.md
@@ -44,7 +44,7 @@ Records are also supported for both serialization and deserialization, as shown
:::code language="csharp" source="snippets/how-to-contd/csharp/Records.cs":::
-You can apply any of the attributes to the property names, using the `property:` target on the attribute. For more information on positional records, see the article on [records](../../../csharp/language-reference/builtin-types/record.md#positional-syntax-for-property-definition) in the C# language reference.
+You can apply any of the attributes to the property names, using the `property:` target on the attribute. For more information on positional records, see the article on [records](../../../csharp/language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) in the C# language reference.
## Non-public members and property accessors