diff --git a/.github/workflows/check-for-build-warnings.yml b/.github/workflows/check-for-build-warnings.yml index ff07cff862df4..839162daa8eef 100644 --- a/.github/workflows/check-for-build-warnings.yml +++ b/.github/workflows/check-for-build-warnings.yml @@ -16,7 +16,7 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-orphaned-articles.yml b/.github/workflows/cleanrepo-orphaned-articles.yml index 4ca2ca57f05fe..a6548235fc033 100644 --- a/.github/workflows/cleanrepo-orphaned-articles.yml +++ b/.github/workflows/cleanrepo-orphaned-articles.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-orphaned-images.yml b/.github/workflows/cleanrepo-orphaned-images.yml index b6f1d137502f5..3fd268d76b87c 100644 --- a/.github/workflows/cleanrepo-orphaned-images.yml +++ b/.github/workflows/cleanrepo-orphaned-images.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-orphaned-includes.yml b/.github/workflows/cleanrepo-orphaned-includes.yml index 1268f7e4b9f4d..f184e56f0e50f 100644 --- a/.github/workflows/cleanrepo-orphaned-includes.yml +++ b/.github/workflows/cleanrepo-orphaned-includes.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-orphaned-snippets.yml b/.github/workflows/cleanrepo-orphaned-snippets.yml index 1f401a4b78890..c7b2d1a2d0fc8 100644 --- a/.github/workflows/cleanrepo-orphaned-snippets.yml +++ b/.github/workflows/cleanrepo-orphaned-snippets.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-redirect-hops.yml b/.github/workflows/cleanrepo-redirect-hops.yml index 665d12074e6ce..baaa997a44bc7 100644 --- a/.github/workflows/cleanrepo-redirect-hops.yml +++ b/.github/workflows/cleanrepo-redirect-hops.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-relative-links.yml b/.github/workflows/cleanrepo-relative-links.yml index 46090fd8d348f..7781cda6b90d9 100644 --- a/.github/workflows/cleanrepo-relative-links.yml +++ b/.github/workflows/cleanrepo-relative-links.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/cleanrepo-replace-redirects.yml b/.github/workflows/cleanrepo-replace-redirects.yml index 31d86e66d55cc..d81eb8b6c0004 100644 --- a/.github/workflows/cleanrepo-replace-redirects.yml +++ b/.github/workflows/cleanrepo-replace-redirects.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/dependabot-bot.yml b/.github/workflows/dependabot-bot.yml index 8ccd537eed88e..cdf341425783b 100644 --- a/.github/workflows/dependabot-bot.yml +++ b/.github/workflows/dependabot-bot.yml @@ -26,7 +26,7 @@ jobs: # Checkout the repo into the workspace within the VM steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 8c9c71d66de16..29013db85959a 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/do-not-merge-label-check.yml b/.github/workflows/do-not-merge-label-check.yml index d96e7d47010c4..00cb616126f62 100644 --- a/.github/workflows/do-not-merge-label-check.yml +++ b/.github/workflows/do-not-merge-label-check.yml @@ -22,7 +22,7 @@ jobs: - 'DO NOT MERGE' steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/docs-verifier.yml b/.github/workflows/docs-verifier.yml index fc42b6d42cd56..ee8896a3f3bdf 100644 --- a/.github/workflows/docs-verifier.yml +++ b/.github/workflows/docs-verifier.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/live-protection.yml b/.github/workflows/live-protection.yml index 3394a8905d9cd..f6722068e9213 100644 --- a/.github/workflows/live-protection.yml +++ b/.github/workflows/live-protection.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml index 4286db0c2d48d..8d054da316bd3 100644 --- a/.github/workflows/markdownlint.yml +++ b/.github/workflows/markdownlint.yml @@ -22,12 +22,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: DavidAnson/markdownlint-cli2-action@ded1f9488f68a970bc66ea5619e13e9b52e601cd # v23.2.0 + - uses: DavidAnson/markdownlint-cli2-action@8de2aa07cae85fd17c0b35642db70cf5495f1d25 # v24.0.0 with: config: ".markdownlint-cli2.jsonc" globs: "**/*.md" diff --git a/.github/workflows/quest-bulk.yml b/.github/workflows/quest-bulk.yml index 273be8e13b940..300d807a90df3 100644 --- a/.github/workflows/quest-bulk.yml +++ b/.github/workflows/quest-bulk.yml @@ -28,7 +28,7 @@ jobs: if: ${{ github.repository_owner == 'dotnet' }} steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/quest.yml b/.github/workflows/quest.yml index 2500764222d4a..2e89a38897475 100644 --- a/.github/workflows/quest.yml +++ b/.github/workflows/quest.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index b945b5b832f0b..354b8f02494df 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v3.29.5 + uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v3.29.5 with: sarif_file: results.sarif diff --git a/.github/workflows/snippets5000.yml b/.github/workflows/snippets5000.yml index 8cbaf70631d0a..d1d583065917c 100644 --- a/.github/workflows/snippets5000.yml +++ b/.github/workflows/snippets5000.yml @@ -31,7 +31,7 @@ jobs: steps: # Checkout the repository for the PR - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.github/workflows/version-sweep.yml b/.github/workflows/version-sweep.yml index 80320bf6ac6db..0eb70dd979f85 100644 --- a/.github/workflows/version-sweep.yml +++ b/.github/workflows/version-sweep.yml @@ -34,7 +34,7 @@ jobs: # Start the .NET version updater action # A composite of the .NET Version Sweeper and the .NET Upgrade Assistant - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 25c1563e1f38b..e9be684712504 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -310,6 +310,10 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0417.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/generic-type-parameters-errors" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0446.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs0467.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/lambda-expression-errors" @@ -438,6 +442,10 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1564.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1579.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1614.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/attribute-usage-errors" @@ -446,6 +454,10 @@ "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1616.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/invalid-build-command-line" }, + { + "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1640.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/language-reference/compiler-messages/cs1656.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors" @@ -1848,6 +1860,10 @@ "source_path_from_root": "/docs/csharp/misc/cs0200.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/property-declaration-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0202.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/misc/cs0206.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/ref-modifiers-errors" @@ -1912,6 +1928,10 @@ "source_path_from_root": "/docs/csharp/misc/cs0227.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/unsafe-code-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0230.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/misc/cs0231.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/params-arrays" @@ -1988,6 +2008,18 @@ "source_path_from_root": "/docs/csharp/misc/cs0277.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/interface-implementation-errors" }, + { + "source_path_from_root": "/docs/csharp/misc/cs0278.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, + { + "source_path_from_root": "/docs/csharp/misc/cs0279.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, + { + "source_path_from_root": "/docs/csharp/misc/cs0280.md", + "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/foreach-diagnostics" + }, { "source_path_from_root": "/docs/csharp/misc/cs0282.md", "redirect_url": "/dotnet/csharp/language-reference/compiler-messages/partial-declarations" diff --git a/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj b/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj index 57c63f69ac49b..5f7c914e6bacd 100644 --- a/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj +++ b/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/ai/quickstarts/snippets/prompt-completion/openai/ExtensionsOpenAI.csproj b/docs/ai/quickstarts/snippets/prompt-completion/openai/ExtensionsOpenAI.csproj index e0a3251bd6984..069e51cd638b5 100644 --- a/docs/ai/quickstarts/snippets/prompt-completion/openai/ExtensionsOpenAI.csproj +++ b/docs/ai/quickstarts/snippets/prompt-completion/openai/ExtensionsOpenAI.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj b/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj index a2a04fd9152f0..e56db72962f4b 100644 --- a/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj +++ b/docs/ai/snippets/prompt-engineering/multi-turn-chat.csproj @@ -10,7 +10,7 @@ - + diff --git a/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj b/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj index d8803776079f8..feb8a4d60d635 100644 --- a/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj +++ b/docs/core/diagnostics/snippets/resource-monitoring-with-manual-metrics/resource-monitoring-with-manual-metrics.csproj @@ -14,7 +14,7 @@ - + diff --git a/docs/core/extensions/caching.md b/docs/core/extensions/caching.md index 43aa372ea75ae..b44ec09ca4759 100644 --- a/docs/core/extensions/caching.md +++ b/docs/core/extensions/caching.md @@ -365,6 +365,8 @@ Consider any of the available implementations of the `IDistributedCache` from th - [`Microsoft.Extensions.Caching.SqlServer`](https://www.nuget.org/packages/Microsoft.Extensions.Caching.SqlServer) - [`Microsoft.Extensions.Caching.StackExchangeRedis`](https://www.nuget.org/packages/Microsoft.Extensions.Caching.StackExchangeRedis) +- [`Microsoft.Extensions.Caching.Cosmos`](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Cosmos) +- [`Microsoft.Extensions.Caching.Postgres`](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres) - [`NCache.Microsoft.Extensions.Caching.OpenSource`](https://www.nuget.org/packages/NCache.Microsoft.Extensions.Caching.OpenSource) ### Distributed caching API diff --git a/docs/core/extensions/dependency-injection/snippets/anti-patterns/di-anti-patterns.csproj b/docs/core/extensions/dependency-injection/snippets/anti-patterns/di-anti-patterns.csproj index 47ef684933a27..7e9e96831eb19 100644 --- a/docs/core/extensions/dependency-injection/snippets/anti-patterns/di-anti-patterns.csproj +++ b/docs/core/extensions/dependency-injection/snippets/anti-patterns/di-anti-patterns.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/extensions/snippets/http/generated/generated.csproj b/docs/core/extensions/snippets/http/generated/generated.csproj index 757bcbb57b017..ea326224db9cf 100644 --- a/docs/core/extensions/snippets/http/generated/generated.csproj +++ b/docs/core/extensions/snippets/http/generated/generated.csproj @@ -11,7 +11,7 @@ - + diff --git a/docs/core/install/linux-snap-sdk.md b/docs/core/install/linux-snap-sdk.md index b781041c1480a..ad3949fbf837c 100644 --- a/docs/core/install/linux-snap-sdk.md +++ b/docs/core/install/linux-snap-sdk.md @@ -3,7 +3,7 @@ title: Install .NET SDK on Linux with Snap description: Learn about how to install the .NET SDK snap package. Canonical maintains and supports .NET-related snap packages. author: adegeo ms.author: adegeo -ms.date: 04/23/2026 +ms.date: 07/15/2026 ms.topic: install-set-up-deploy ms.custom: linux-related-content, updateeachrelease ai-usage: ai-assisted @@ -16,6 +16,9 @@ This article describes how to install the .NET SDK snap package. .NET SDK snap p A snap is a bundle of an app and its dependencies that works across many different Linux distributions. Snaps are discoverable and installable from the Snap Store. For more information about Snap, see [Get started](https://snapcraft.io/docs/tutorials/get-started/#tutorials-get-started). +> [!IMPORTANT] +> If you install .NET with Snap, use Snap to manage all your .NET installations. Avoid mixing Snap with other installation methods, such as a package manager or the scripted install, because mixing methods can cause conflicts. + > [!CAUTION] > Snap installations of .NET may have problems running [.NET tools](../tools/global-tools.md). If you wish to use .NET tools, we recommend that you install .NET using the [`dotnet-install` script](linux-scripted-manual.md#scripted-install) or the package manager for the particular Linux distribution. > @@ -36,60 +39,48 @@ Your Linux distribution might already include snap. Try running `snap` from a te ## 1. Install the SDK -[!INCLUDE [linux-release-wait](includes/linux-release-wait.md)] - -Starting with .NET 9, snap packages for the .NET SDK are published under version-specific identifiers (for example, `dotnet-sdk-90` for .NET 9 and `dotnet-sdk-100` for .NET 10). Prior to .NET 9, all SDK versions were published under the same identifier `dotnet-sdk`, and you specified the version through a channel. Additionally, .NET 9 and later snap packages support both x64 and Arm64 architectures, while earlier versions only support x64. The SDK includes both the ASP.NET Core and .NET runtime, versioned to the SDK. +To install the .NET SDK, use version-specific snap package identifiers because this approach lets you install and manage multiple SDK versions side by side. For example, use `dotnet-sdk-80` for .NET 8 and `dotnet-sdk-100` for .NET 10. The SDK includes both the ASP.NET Core and .NET runtime, versioned to the SDK. This article uses the .NET 10 SDK snap package; if you're using a different package, substitute it. > [!TIP] -> The [Snapcraft .NET SDK package page](https://snapcraft.io/dotnet-sdk) ([.NET 9](https://snapcraft.io/dotnet-sdk-90), [.NET 10](https://snapcraft.io/dotnet-sdk-100)) includes distribution-specific instructions on how to install Snapcraft and .NET. +> The Snapcraft .NET SDK package page ([.NET 8](https://snapcraft.io/dotnet-sdk-80), [.NET 9](https://snapcraft.io/dotnet-sdk-90), [.NET 10](https://snapcraft.io/dotnet-sdk-100)) includes distribution-specific instructions on how to install Snapcraft and .NET. 01. Open a terminal. 01. Use `snap install` to install the .NET SDK snap package. - The `--classic` parameter is required. - - - **For .NET 9 and later** - - Install the version-specific package. For example, the following command installs .NET SDK 10: - - ```bash - sudo snap install dotnet-sdk-100 --classic - ``` + The following command installs .NET SDK 10: - - **For .NET 8 and earlier** - - Install from the `dotnet-sdk` package and specify a channel. If this parameter is omitted, `latest/stable` is used. For example, the following command installs .NET SDK 8: - - ```bash - sudo snap install dotnet-sdk --classic --channel 8.0/stable - ``` - -The `dotnet` snap alias is automatically created and mapped to the snap package's `dotnet` command. + ```bash + sudo snap install dotnet-sdk-100 + ``` -The following table lists the snap packages and channels you can install: +The following table lists the .NET SDK snap packages you can install: -| .NET version | Snap package or channel | -|--------------|----------------------------------------| -| 10 (LTS) | `dotnet-sdk-100` (preview) | -| 9 (STS) | `dotnet-sdk-90` | -| 8 (LTS) | `dotnet-sdk --channel 8.0/stable` | +| .NET version | Snap package | +|--------------|------------------| +| 10 (LTS) | `dotnet-sdk-100` | +| 9 (STS) | `dotnet-sdk-90` | +| 8 (LTS) | `dotnet-sdk-80` | -## 2. Export the install location +## 2. Map the dotnet command -The `DOTNET_ROOT` environment variable is often used by tools to determine where .NET is installed. When .NET is installed through Snap, this environment variable isn't configured. You should configure the *DOTNET_ROOT* environment variable in your profile. The path to the snap uses the following format: `/snap/{package}/current`. +Because Snap doesn't create an unversioned `dotnet` command, create a symbolic link to make `dotnet` available system-wide. Create this link only if you want to map the `dotnet` command to this specific Snap installation. If you already have .NET installed through another method and you create this link, it overwrites that mapping. -For .NET 9 and later, use the version-specific package name: +If `/usr/local/bin/dotnet` already exists, remove it before you create the link. ```bash -export DOTNET_ROOT=/snap/dotnet-sdk-100/current +sudo ln -s /snap/dotnet-sdk-100/current/usr/bin/dotnet /usr/local/bin/dotnet ``` -For .NET 8 and earlier, use the shared package name: +## 3. Export the install location + +Configure the `DOTNET_ROOT` environment variable in your shell profile because tools use it to determine where .NET is installed. Snap installations don't set this variable automatically. The path uses the following format: `/snap/{package}/current/usr/lib/dotnet`. ```bash -export DOTNET_ROOT=/snap/dotnet-sdk/current +export DOTNET_ROOT=/snap/dotnet-sdk-100/current/usr/lib/dotnet ``` +Replace `100` with the SDK version you installed, such as `80` for .NET 8 or `90` for .NET 9. + ### Export the environment variable permanently The preceding `export` command only sets the environment variable for the terminal session in which it was run. @@ -100,11 +91,13 @@ You can edit your shell profile to permanently add the commands. There are many - **Korn Shell**: _~/.kshrc_ or _.profile_ - **Z Shell**: _~/.zshrc* or _.zprofile_ -Edit the appropriate source file for your shell and add the export command for your installed .NET version. For .NET 9+, use `export DOTNET_ROOT=/snap/dotnet-sdk-100/current` (adjust the version number as needed). For .NET 8 and earlier, use `export DOTNET_ROOT=/snap/dotnet-sdk/current`. +Edit the appropriate source file for your shell, add the export command for your installed .NET version, and save your changes. + +For example: `export DOTNET_ROOT=/snap/dotnet-sdk-100/current/usr/lib/dotnet`. -## 3. Use the .NET CLI +## 4. Use the .NET CLI -Open a terminal and type `dotnet`. +Open a terminal and run the `dotnet` command. ```dotnetcli dotnet @@ -130,27 +123,10 @@ To learn how to use the .NET CLI, see [.NET CLI overview](../tools/index.md). ## Troubleshooting -- [The dotnet terminal command doesn't work](#the-dotnet-terminal-command-doesnt-work) - [Can't install Snap on WSL2](#cant-install-snap-on-wsl2) - [Can't resolve the dotnet command or SDK](#cant-resolve-the-dotnet-command-or-sdk) - [TLS/SSL Certificate errors](#tlsssl-certificate-errors) -### The dotnet terminal command doesn't work - -Snap packages can map an alias to a command provided by the package. By default, the .NET SDK snap packages create an alias for the `dotnet` command. If the alias wasn't created or was previously removed, use the following command to map the alias. - -For .NET 9 and later: - -```bash -sudo snap alias dotnet-sdk-100.dotnet dotnet -``` - -For .NET 8 and earlier: - -```bash -sudo snap alias dotnet-sdk.dotnet dotnet -``` - ### Can't install Snap on WSL2 `systemd` must be enabled on the WSL2 instance before Snap can be installed. @@ -175,26 +151,8 @@ It's common for other apps, such as a code IDE or an extension in Visual Studio Try the following steps to fix the issue: -01. Making sure that you [export the `DOTNET_ROOT` environment variable permanently](#export-the-environment-variable-permanently). - -01. Try to symbolic link the snap `dotnet` executable to the location that the program is looking for. - - Two common paths the `dotnet` command is looking for are: - - - `/usr/local/bin/dotnet` - - `/usr/share/dotnet` - - Use the following command to create a symbolic link to the snap package. For .NET 9 and later, use the version-specific package name: - - ```bash - ln -s /snap/dotnet-sdk-100/current/dotnet /usr/local/bin/dotnet - ``` - - For .NET 8 and earlier: - - ```bash - ln -s /snap/dotnet-sdk/current/dotnet /usr/local/bin/dotnet - ``` +01. Complete [2. Map the dotnet command](#2-map-the-dotnet-command). +01. Set the `DOTNET_ROOT` environment variable permanently by following [Export the environment variable permanently](#export-the-environment-variable-permanently). ### TLS/SSL Certificate errors diff --git a/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md b/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md index cf087861d2ac8..f2b5ff74b171d 100644 --- a/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md +++ b/docs/core/porting/github-copilot-app-modernization/includes/how-to-initiate.md @@ -8,7 +8,7 @@ ms.topic: include 1. Start the agent by using one of these methods: - **Visual Studio**: Right-click the solution or project in **Solution Explorer** and select **Modernize**. Alternatively, open the **GitHub Copilot Chat** window and type `@Modernize`. - - **Visual Studio Code**: Open the **GitHub Copilot Chat** panel and type `@modernize-dotnet`. + - **Visual Studio Code**: Open the **GitHub Copilot Chat** panel and type `@upgrade`. - **GitHub Copilot CLI**: Type `@upgrade` followed by your upgrade or migration request. - **GitHub Copilot app**: In the **Agent** picker, select `Upgrade`. diff --git a/docs/core/porting/github-copilot-app-modernization/install.md b/docs/core/porting/github-copilot-app-modernization/install.md index 5d11a84e13744..d877fd6b8490f 100644 --- a/docs/core/porting/github-copilot-app-modernization/install.md +++ b/docs/core/porting/github-copilot-app-modernization/install.md @@ -53,20 +53,20 @@ Before you install, make sure you have: Install as a Visual Studio Code extension: 1. In Visual Studio Code, open the **Extensions** view (Ctrl+Shift+X). -1. Search for **GitHub Copilot modernization**. +1. Search for **GitHub Copilot upgrade**. 1. Select **Install**. -The extension automatically acquires the .NET SDK if it's missing, registers tools, and adds the agent to Copilot Chat as `modernize-dotnet`. +The extension automatically acquires the .NET SDK if it's missing, registers tools, and adds the agent to Copilot Chat as `Upgrade`. ## Verify the installation 1. Open a project in Visual Studio Code. 1. Open the **GitHub Copilot Chat** view. -1. Send `@modernize-dotnet` in chat and confirm the agent responds. +1. Send `@upgrade` in chat and confirm the agent responds. -or- - Select the **Agent** picker and find the `modernize-dotnet` entry. + Select the **Agent** picker and find the `Upgrade` entry. ::: zone-end diff --git a/docs/core/testing/snippets/order-unit-tests/csharp/MSTest.Project/MSTest.Project.csproj b/docs/core/testing/snippets/order-unit-tests/csharp/MSTest.Project/MSTest.Project.csproj index a302956875d7d..1643fefc4f499 100644 --- a/docs/core/testing/snippets/order-unit-tests/csharp/MSTest.Project/MSTest.Project.csproj +++ b/docs/core/testing/snippets/order-unit-tests/csharp/MSTest.Project/MSTest.Project.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/core/testing/snippets/order-unit-tests/csharp/NUnit.TestProject/NUnit.Project.csproj b/docs/core/testing/snippets/order-unit-tests/csharp/NUnit.TestProject/NUnit.Project.csproj index f030dc93843b5..5392d8f285cd0 100644 --- a/docs/core/testing/snippets/order-unit-tests/csharp/NUnit.TestProject/NUnit.Project.csproj +++ b/docs/core/testing/snippets/order-unit-tests/csharp/NUnit.TestProject/NUnit.Project.csproj @@ -10,7 +10,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/docs/core/testing/snippets/order-unit-tests/csharp/XUnit.TestProject/XUnit.Project.csproj b/docs/core/testing/snippets/order-unit-tests/csharp/XUnit.TestProject/XUnit.Project.csproj index 8e2cd77a45744..96b1c4d168d38 100644 --- a/docs/core/testing/snippets/order-unit-tests/csharp/XUnit.TestProject/XUnit.Project.csproj +++ b/docs/core/testing/snippets/order-unit-tests/csharp/XUnit.TestProject/XUnit.Project.csproj @@ -8,7 +8,7 @@ - + all diff --git a/docs/core/whats-new/dotnet-11/libraries.md b/docs/core/whats-new/dotnet-11/libraries.md index de088441a5528..0171900f33de0 100644 --- a/docs/core/whats-new/dotnet-11/libraries.md +++ b/docs/core/whats-new/dotnet-11/libraries.md @@ -2,14 +2,14 @@ title: What's new in .NET libraries for .NET 11 description: Learn about the updates to the .NET libraries for .NET 11. titleSuffix: "" -ms.date: 06/09/2026 +ms.date: 07/14/2026 ai-usage: ai-assisted ms.update-cycle: 3650-days --- # What's new in .NET libraries for .NET 11 -This article describes new features in the .NET libraries for .NET 11. It was last updated for Preview 5. +This article describes new features in the .NET libraries for .NET 11. It was last updated for Preview 6. ## Diagnostics and process execution @@ -53,6 +53,24 @@ The full set of helpers includes: - — specify exactly which OS handles a child process inherits, instead of using the all-or-nothing `UseShellExecute = false` default. - , , and — supply already-open values for redirection without the framework opening new ones. +#### Suspended starts and process lookup + +`System.Diagnostics.Process` adds finer control over starting and finding processes: + +- `ProcessStartInfo.StartSuspended` starts a process in a suspended state on Windows. Pair it with `SafeProcessHandle.Resume` to let it run once you've finished any setup, such as attaching a debugger or configuring job objects. +- `Process.TryGetProcessById` returns `false` instead of throwing when no process with the given ID exists. +- `SafeProcessHandle.Open` and `TryOpen` open a handle to an existing process by ID. + +```csharp +var startInfo = new ProcessStartInfo("worker.exe") { StartSuspended = true }; +using var process = Process.Start(startInfo)!; + +// Attach diagnostics or configure job objects while the process is suspended, +// then call Resume to start execution once your setup is complete. +AttachProfiler(process); +process.SafeHandle.Resume(); +``` + ### Console FORCE_COLOR support .NET console output now honors the [`FORCE_COLOR`](https://force-color.org/) standard alongside the existing `NO_COLOR` support. When `FORCE_COLOR` is set, no longer suppresses ANSI escape codes. This is useful when you pipe `dotnet run` output through `tee`, into a CI log viewer, or through `less -R`: @@ -61,6 +79,31 @@ The full set of helpers includes: FORCE_COLOR=1 dotnet run | tee build.log ``` +## In-memory stream adapters + +Four new `Stream` types wrap common in-memory data so you can pass them to any API that expects a `Stream`, without copying into a `MemoryStream` first: + +- `ReadOnlyMemoryStream` exposes a `ReadOnlyMemory` as a read-only stream. +- `WritableMemoryStream` exposes a writable `Memory` as a fixed-size stream. +- `ReadOnlySequenceStream` exposes a `ReadOnlySequence` (for example, buffers from `System.IO.Pipelines`) as a stream without flattening it. +- `StringStream` reads a `string` or `ReadOnlyMemory` as a stream using a specified encoding. + +```csharp +using System.IO; +using System.Text; + +// Pass a string to an API that takes a Stream, with no intermediate byte[] needed. +using Stream config = new StringStream(yamlText, Encoding.UTF8); +var settings = ParseConfiguration(config); + +// Expose an existing buffer as a read-only stream, for example as an HTTP request body. +ReadOnlyMemory payload = GetPayload(); +using Stream body = new ReadOnlyMemoryStream(payload); +await httpClient.PostAsync(uri, new StreamContent(body)); +``` + +`ReadOnlySequenceStream` is especially useful with `System.IO.Pipelines`, because it streams directly over the segments of a `ReadOnlySequence` instead of allocating a contiguous copy. + ## Text, serialization, and data handling - [String and character enhancements](#string-and-character-enhancements) @@ -171,6 +214,26 @@ let json = System.Text.Json.JsonSerializer.Serialize(Circle 1.5) :::code language="csharp" source="./snippets/csharp/Libraries.cs" id="JsonSerializeAsyncEnumerablePipe"::: +#### C# union type serialization + +`System.Text.Json` can now serialize and deserialize C# union types. The serializer recognizes a union through the new `JsonTypeInfoKind.Union` contract kind, reads and writes the active case, and supports both the reflection-based serializer and the source generator. When you serialize a union, `System.Text.Json` writes the value of whichever case is active, so a union of `int` and `string` round-trips cleanly: + +```json +{ + "id": 1, + "payload": "hello" +} +``` + +```json +{ + "id": 2, + "payload": 42 +} +``` + +The new `JsonUnionAttribute` and `JsonUnionCaseInfo` APIs, along with type-classifier APIs (`JsonTypeClassifier` and `JsonSerializerOptions.TypeClassifiers`), let you customize how cases are discovered and named. Union types are a C# language preview feature. For more information, see [What's new in C# 15](../../../csharp/whats-new/csharp-15.md#union-types). + ### Regular expression improvements #### AnyNewLine option @@ -240,6 +303,7 @@ New overloads on and `, `Vector128`, `Vector256`, `Vector512`, and `Vector` gain a set of lane construction and composition methods that previously required hand-written shuffles. The new methods fall into a few families: + +- **Patterned construction:** `CreateGeometricSequence`, `CreateAlternatingSequence`, and `CreateHarmonicSequence` build a vector from a starting value and a rule. +- **Interleave and de-interleave:** `Zip`, `ZipLower`/`ZipUpper`, `Unzip`, `UnzipEven`/`UnzipOdd`. +- **Rearrange:** The `Concat` family (`ConcatLowerLower`, `ConcatLowerUpper`, `ConcatUpperLower`, `ConcatUpperUpper`) and `Reverse`. + +```csharp +using System.Runtime.Intrinsics; + +// {1, 2, 4, 8} — each lane is the previous lane times two +Vector128 powers = Vector128.CreateGeometricSequence(1, 2); + +// Interleave two vectors lane-by-lane +(Vector128 lower, Vector128 upper) = + Vector128.Zip(Vector128.Create(1), Vector128.Create(2)); +``` + +These building blocks are useful for image processing, audio digital signal processing (DSP), and other SIMD-intensive workloads that need fine-grained control over vector element layout, without falling back to platform-specific intrinsics. + ### Low-level I/O improvements - [SafeFileHandle pipe support](#safefilehandle-pipe-support) @@ -405,6 +490,8 @@ These constants can be used with the `StringSyntax` attribute to provide better - [Configuration binding](#configuration-binding) - [MemoryCache OpenTelemetry metrics](#memorycache-opentelemetry-metrics) - [Options builder validation improvements](#options-builder-validation-improvements) +- [Asynchronous validation with DataAnnotations](#asynchronous-validation-with-dataannotations) +- [Activity tracing configuration](#activity-tracing-configuration) ### Configuration binding @@ -455,6 +542,62 @@ services.AddOptions() .Validate(); ``` +### Asynchronous validation with DataAnnotations + +`System.ComponentModel.DataAnnotations` now supports asynchronous validation. A validation rule that needs to do I/O—a database lookup or a remote API call—can now run without blocking a thread. There are three new ways to express an async rule: + +- Derive from `AsyncValidationAttribute` and override its `IsValidAsync` method. +- Implement `IAsyncValidatableObject` on the model. +- Call the new `Validator.ValidateObjectAsync`, `TryValidateObjectAsync`, `ValidatePropertyAsync`, and `ValidateValueAsync` methods. + +```csharp +using System; +using System.ComponentModel.DataAnnotations; + +public sealed class ValidVatNumberAttribute : AsyncValidationAttribute +{ + protected override ValidationResult? IsValid(object? value, ValidationContext context) => + throw new InvalidOperationException("Validate this attribute with IsValidAsync."); + + protected override async Task IsValidAsync( + object? value, ValidationContext context, CancellationToken cancellationToken) + { + var registry = context.GetRequiredService(); + return await registry.IsRegisteredAsync((string?)value, cancellationToken) + ? ValidationResult.Success + : new ValidationResult("That VAT number isn't registered with the tax authority."); + } +} + +public class Invoice +{ + [Required] + [StringLength(14, MinimumLength = 8)] + [RegularExpression(@"^[A-Z]{2}[A-Z0-9]+$")] + [ValidVatNumber] // asynchronous + public string VatNumber { get; set; } = ""; +} + +var context = new ValidationContext(model, serviceProvider, items: null); +await Validator.ValidateObjectAsync(model, context, validateAllProperties: true); +``` + +`Microsoft.Extensions.Options` gains matching support: options can be validated asynchronously, including at startup through the new `IAsyncStartupValidator`. This lets an app fail fast when an option that requires a network check is misconfigured. + +### Activity tracing configuration + +A new tracing configuration API in `Microsoft.Extensions.Diagnostics` lets you turn `Activity` tracing on and off with rules instead of wiring up `ActivityListener` instances manually. Call `AddTracing` and describe which activity sources, operations, and listeners to enable or disable. Rules can be driven from configuration, so tracing can be tuned without a redeploy. + +```csharp +builder.Services.AddTracing(tracing => +{ + tracing.EnableTracing(sourceName: "MyCompany.Orders"); + tracing.DisableTracing(sourceName: "MyCompany.Orders", operationName: "HealthCheck"); +}); +``` + +The same release adds `ActivitySourceFactory` and unseals `ActivitySource`, which together support factory-driven creation and refreshable listeners. + ## Cryptography - [X25519 Diffie-Hellman key exchange](#x25519-diffie-hellman-key-exchange) diff --git a/docs/core/whats-new/dotnet-11/overview.md b/docs/core/whats-new/dotnet-11/overview.md index 8e48c0dc13b9a..3749e1b49ac1e 100644 --- a/docs/core/whats-new/dotnet-11/overview.md +++ b/docs/core/whats-new/dotnet-11/overview.md @@ -2,14 +2,14 @@ title: What's new in .NET 11 description: Learn about the new features introduced in .NET 11 for the runtime, libraries, and SDK. Also find links to what's new in other areas, such as ASP.NET Core. titleSuffix: "" -ms.date: 06/09/2026 +ms.date: 07/14/2026 ai-usage: ai-assisted ms.update-cycle: 3650-days --- # What's new in .NET 11 -This article describes new features in .NET 11. It was last updated for Preview 5. +This article describes new features in .NET 11. It was last updated for Preview 6. .NET 11 is currently in preview. The final release is expected in November 2026. You can [download .NET 11 here](https://dotnet.microsoft.com/download/dotnet/11.0). @@ -19,7 +19,11 @@ The .NET 11 runtime includes: - Updated minimum hardware requirements for x86/x64 and Arm64 architectures, requiring more modern instruction sets to improve performance and reduce maintenance complexity. - Runtime-native async (Runtime Async), which produces cleaner stack traces and lower overhead. Runtime Async no longer requires `true` for projects that target `net11.0`. The runtime libraries themselves are compiled with `runtime-async=on`. -- JIT improvements for bounds check elimination, redundant checked context removal, switch expression folding, constant-folding `SequenceEqual`, and redundant branch elimination. There are also new Arm SVE2 intrinsics and improved hardware-intrinsic cost modeling. +- Runtime Async performance improvements, including JIT compilation of a dedicated runtime-async version of synchronous task-returning methods, async continuations that opt out of `ExecutionContext` capture when no ambient state is in use, and tail-merged suspension points that reduce generated code size. +- JIT improvements for bounds check elimination, redundant checked context removal, switch expression folding, constant-folding `SequenceEqual`, and redundant branch elimination. There are also new Arm SVE2 intrinsics, improved hardware-intrinsic cost modeling, and a faster `Math.BigMul` on x64 that emits a single `MUL` instruction. +- In-process crash report logging on mobile platforms that captures the managed stack trace and runtime state before the process exits. +- NativeAOT faster interface dispatch using a shared dispatch helper, reducing binary size at call sites and improving throughput for interface-heavy workloads. +- SIMD lane construction and composition APIs (`CreateGeometricSequence`, `Zip`, `Unzip`, and the `Concat` family) across `Vector128`, `Vector256`, `Vector512`, `Vector64`, and `Vector`. For more information, see [What's new in the .NET 11 runtime](runtime.md). @@ -27,9 +31,9 @@ For more information, see [What's new in the .NET 11 runtime](runtime.md). The .NET 11 libraries include new APIs for: -- expansion with run-and-capture helpers, fire-and-forget launches, `SafeProcessHandle` lifecycle methods, and tighter handle control. +- expansion with run-and-capture helpers, fire-and-forget launches, `SafeProcessHandle` lifecycle methods, tighter handle control, and new `ProcessStartInfo.StartSuspended` for suspended starts and `Process.TryGetProcessById` for safe process lookup. - Compression, including improved Base64 APIs, new methods for ZIP archive entries, Zstandard compression in , and CRC32 validation when reading ZIP entries. -- System.Text.Json improvements, including generic type info retrieval, , per-member naming policy overrides, type-level ignore conditions, F# discriminated union support, with options, and `SerializeAsyncEnumerable` overloads for `PipeWriter` targets and top-level values (NDJSON) output. +- System.Text.Json improvements, including generic type info retrieval, , per-member naming policy overrides, type-level ignore conditions, F# discriminated union support, with options, `SerializeAsyncEnumerable` overloads for `PipeWriter` targets and top-level values (NDJSON) output, and serialization of C# union types. - Built-in OpenTelemetry metrics for . - Discriminated-union scaffolding (`UnionAttribute` and `IUnion`) in . - Tar archive format selection and GNU sparse format 1.0 support. @@ -42,6 +46,10 @@ The .NET 11 libraries include new APIs for: - factory method that creates a comparer from a key selector. - for HTTP/3 stream prioritization. - Video MIME type constants in . +- Four new `Stream` types (`ReadOnlyMemoryStream`, `WritableMemoryStream`, `ReadOnlySequenceStream`, `StringStream`) that wrap in-memory data without copying. +- Asynchronous validation in `System.ComponentModel.DataAnnotations` via `AsyncValidationAttribute`, `IAsyncValidatableObject`, and new `Validator.ValidateObjectAsync` methods. +- Activity tracing configuration using rules in `Microsoft.Extensions.Diagnostics`, enabling declarative control of `Activity` tracing without wiring up `ActivityListener` instances manually. +- Cross-lane vector operations including `CreateGeometricSequence`, `Zip`, `Unzip`, and the `Concat` family on `Vector128`, `Vector256`, `Vector512`, `Vector64`, and `Vector`. For more information, see [What's new in the .NET 11 libraries](libraries.md). @@ -52,11 +60,16 @@ The .NET 11 SDK includes: - Smaller SDK installers on Linux and macOS through assembly deduplication, with additional savings by skipping crossgen for `DotnetTools`-only assemblies. - Improved [CA1873](../../../fundamentals/code-analysis/quality-rules/ca1873.md) code analyzer with reduced noise and clearer diagnostic messages. - Support for creating and editing solution filters (`.slnf`) from the `dotnet sln` CLI. -- File-based app support for `#:include` to split apps across multiple files. +- File-based app support for `#:include` to split apps across multiple files, and `#:include ./libs/MyLib.dll` to include compiled DLL references directly. - A new `dotnet run -e` option to pass environment variables from the command line. - `dotnet watch` improvements, including Aspire app-host integration, automatic crash recovery, and device selection for MAUI and mobile projects. - OpenTelemetry replaces Application Insights for CLI telemetry. -- Foundation for a NativeAOT entry point for the `dotnet` CLI. +- NativeAOT CLI entry point that serves the full command surface—including `--help` for all built-in commands and tool/external-command launches—out-of-process from the AOT path, skipping managed CLI startup. +- `dotnet test` improvements, including `--no-dependencies`, `DOTNET_TEST_RUNNER` environment variable, `--use-current-runtime`, `--test-modules` exclusion patterns, per-assembly test counts, and live display of in-flight tests. +- Built-in test templates support xUnit v3 (defaulting to Microsoft.Testing.Platform) and NUnit with an opt-in `--test-runner` option. +- Multi-architecture container image builds with Podman using the SDK's container publishing support. +- TypeScript compilation outputs from Razor Class Libraries now integrate correctly with the Static Web Assets pipeline. +- The `dotnet` CLI no longer suppresses the MSBuild build server when `DOTNET_CLI_USE_MSBUILD_SERVER` is unset, and the OTLP telemetry exporter activates on any standard `OTEL_EXPORTER_OTLP_*` environment variable. For more information, see [What's new in the SDK for .NET 11](sdk.md). diff --git a/docs/core/whats-new/dotnet-11/runtime.md b/docs/core/whats-new/dotnet-11/runtime.md index 54aea0007b122..02b7680a1b1c7 100644 --- a/docs/core/whats-new/dotnet-11/runtime.md +++ b/docs/core/whats-new/dotnet-11/runtime.md @@ -2,14 +2,14 @@ title: What's new in .NET 11 runtime description: Learn about the new features introduced in the .NET 11 runtime. titleSuffix: "" -ms.date: 06/09/2026 +ms.date: 07/14/2026 ai-usage: ai-assisted ms.update-cycle: 3650-days --- # What's new in the .NET 11 runtime -This article describes new features in the .NET runtime for .NET 11. It was last updated for Preview 5. +This article describes new features in the .NET runtime for .NET 11. It was last updated for Preview 6. ## Updated minimum hardware requirements @@ -128,6 +128,21 @@ Runtime Async supports NativeAOT and ReadyToRun compilation. This extends the fe Breakpoints now bind correctly inside runtime-async methods, and the debugger can step through `await` boundaries without jumping into compiler-generated infrastructure. +### Runtime Async performance improvements + +Preview 6 adds several performance improvements to Runtime Async: + +- **JIT async support:** The JIT compiles a dedicated runtime-async version of a synchronous, task-returning method rather than delegating through a thunk. The JIT turns the method's tail calls into runtime-async calls and awaits the task that would otherwise be returned, eliminating an extra layer of indirection. +- **Tail-merged suspension points:** The JIT tail-merges async suspension points so generated code is smaller. +- **Cached continuations:** Continuations used for runtime-async callable task thunks are cached and reused. +- **Pooled methods opt out:** Methods that are already pooled opt out of runtime-async, avoiding redundant work. + +#### Async continuations without ExecutionContext + +Async continuations can now opt out of `ExecutionContext` capture and restore. `ExecutionContext` carries ambient state—such as `AsyncLocal` values—across `await` points. Every `Task` continuation previously captured a snapshot of the context and restored it before running, even when no `AsyncLocal` state was in use and the restore was a no-op. + +The runtime now detects when a continuation has nothing to restore and skips the capture/restore cycle entirely. `Task`, `Task`, `ValueTask`, and `ValueTask` all benefit from this change, as does the runtime-async implementation path. Applications that use `ConfigureAwait(false)` and `AsyncLocal` sparingly see reduced overhead in high-throughput async code paths. + ## JIT improvements - **Bounds check elimination:** The just-in-time (JIT) compiler now eliminates bounds checks for the common pattern where an index plus a constant is compared against a length, such as `i + cns < len`. It also eliminates more redundant bounds checks for index-from-end access (for example, `values[^1]`). These improvements reduce redundant checks in tight loops and improve throughput for array and span operations. @@ -136,6 +151,10 @@ Breakpoints now bind correctly inside runtime-async methods, and the debugger ca - **Faster uint-to-float/double casts:** Casting `uint` to `float` or `double` is faster on pre-AVX-512 x86 hardware. - **Devirtualization in ReadyToRun images:** ReadyToRun (R2R) images can now devirtualize non-shared generic virtual method calls, improving performance of ahead-of-time compiled code for generic scenarios. - **SVE2 intrinsics:** New Arm SVE2 (Scalable Vector Extension 2) intrinsics are available: `ShiftRightLogicalNarrowingSaturate(Even|Odd)`. These expand the set of vectorized operations available on Arm hardware that supports SVE2. +- **`Math.BigMul` on x64:** `Math.BigMul(long, long, out long)` is now significantly faster on x64. The JIT generates a single `MUL r/m64` instruction when both operands are 64-bit values and the caller requests the high half of the result, eliminating the previous helper call. +- **Single-IG prolog restriction removed:** The JIT no longer requires the function prolog to fit in a single instruction group (IG). Complex prologues with many saved registers, large stack allocations, or runtime-async state setup no longer trigger fallback paths. +- **`SELECT(cond, cns, cns)` folding:** The JIT now folds conditional selects whose two branches both produce the same constant into just that constant—for example, `condition ? 42 : 42` becomes `42`. This fold eliminates unnecessary comparisons that can appear after earlier optimizations unify branches. +- **ARM64 `Vector` by reference for SVE:** When the runtime is compiled with ARM SVE support, `Vector` values are passed by reference rather than by value, aligning with the ARM calling convention for scalable types and enabling better code generation for SVE-intensive code. For better performance and code quality, .NET 11 adds several more JIT optimizations: @@ -218,6 +237,39 @@ Browser and WebAssembly support has several improvements: The .NET runtime can now initialize on machines with more than 1024 logical processors. Previously, `sched_getaffinity` was called with the default `cpu_set_t` (capped at 1024), causing initialization to fail on high-core-count servers. The runtime now allocates the CPU set dynamically. The GC retains its 1024-heap limit, but the CPU count limit is removed. +## In-process crash report logging + +A new in-process crash reporting mechanism captures diagnostic information from within the crashing process before it terminates. Previously, crash diagnostics were collected by an out-of-process monitor. While the out-of-process approach is safe, it can miss information that's only available inside the dying process. The new in-process path logs the managed stack trace, module list, and key runtime state to a well-known path before the process exits. + +This capability is specific to mobile platforms. + +## NativeAOT: faster interface dispatch + +NativeAOT now uses a dispatch helper for interface method calls. Instead of a direct fat-pointer call sequence, the runtime routes interface dispatch through a shared helper that can be patched to the correct implementation after the call site warms up. This reduces the binary size of interface call sites and improves throughput on workloads with many interface method calls. + +## SIMD lane construction and composition + +`System.Runtime.Intrinsics` now includes lane construction and composition APIs for hardware vector types. The new APIs let you construct a vector from individually specified lanes and extract or reorder lanes between vectors. This enables precise, portable control over SIMD vector element placement without falling back to platform-specific intrinsics. + +The new methods fall into a few families: + +- **Patterned construction:** `CreateGeometricSequence`, `CreateAlternatingSequence`, and `CreateHarmonicSequence` build a vector from a starting value and a rule. +- **Interleave and de-interleave:** `Zip`, `ZipLower`/`ZipUpper`, `Unzip`, `UnzipEven`/`UnzipOdd`. +- **Rearrange:** The `Concat` family (`ConcatLowerLower`, `ConcatLowerUpper`, `ConcatUpperLower`, `ConcatUpperUpper`) and `Reverse`. + +```csharp +using System.Runtime.Intrinsics; + +// {1, 2, 4, 8} — each lane is the previous lane times two +Vector128 powers = Vector128.CreateGeometricSequence(1, 2); + +// Interleave two vectors lane-by-lane +(Vector128 lower, Vector128 upper) = + Vector128.Zip(Vector128.Create(1), Vector128.Create(2)); +``` + +These APIs are available on `Vector128`, `Vector256`, `Vector512`, `Vector64`, and `Vector`. They're building blocks for image processing, audio digital signal processing (DSP), and other SIMD-intensive workloads that need fine-grained control over vector element layout. + ## See also - [What's new in .NET libraries for .NET 11](libraries.md) diff --git a/docs/core/whats-new/dotnet-11/sdk.md b/docs/core/whats-new/dotnet-11/sdk.md index 1f51e6d06596f..e0ab112f7e596 100644 --- a/docs/core/whats-new/dotnet-11/sdk.md +++ b/docs/core/whats-new/dotnet-11/sdk.md @@ -2,14 +2,14 @@ title: What's new in the SDK and tooling for .NET 11 description: Learn about the new .NET SDK features introduced in .NET 11. titleSuffix: "" -ms.date: 06/09/2026 +ms.date: 07/14/2026 ai-usage: ai-assisted ms.update-cycle: 3650-days --- # What's new in the SDK and tooling for .NET 11 -This article describes new features and enhancements in the .NET SDK for .NET 11. It was last updated for Preview 5. +This article describes new features and enhancements in the .NET SDK for .NET 11. It was last updated for Preview 6. ## SDK footprint @@ -205,18 +205,92 @@ The `dotnet` CLI now uses OpenTelemetry (OTel) with Azure Monitor and OTLP expor ### NativeAOT entry point for the dotnet CLI -To enable near-instant startup for common CLI invocations, .NET 11 lays the groundwork for a NativeAOT-compiled `dotnet` CLI host. The work introduces three layers: +To enable near-instant startup for common CLI invocations, .NET 11 is laying the groundwork for a NativeAOT-compiled `dotnet` CLI host. Earlier previews packaged the NativeAOT `dotnet-aot` library and gated it behind `DOTNET_CLI_ENABLEAOT=true`. Preview 6 keeps the off-by-default behavior, but unifies the managed and NativeAOT CLI parsers into a single shared implementation, so the AOT fast path now parses, validates, and renders `--help` for every command—not just the small subset it previously handled. -- `dn.exe` — a NativeAOT host that resolves `DOTNET_ROOT` and `hostfxr` and marshals arguments into a NativeAOT shared library. This is for SDK-repository dogfooding, not production usage. -- `dotnet-aot.dll` — a NativeAOT shared library that handles simple commands such as `--version` and `--info` directly, and falls back to the full managed CLI for everything else. -- `dotnet.dll` — the existing managed CLI, with `#if CLI_AOT` conditionals so the same source files can be compiled into both paths. +Commands that can run entirely without the managed runtime execute natively. Every other command transparently falls back to the managed CLI. In Preview 6, the following commands are fully served from the AOT path: -The goal is near-instant startup for the most common CLI invocations while preserving full functionality for the rest. The new entry point isn't the default `dotnet` binary yet. +- `dotnet --version`, `dotnet --info`, `dotnet --help` +- `dotnet --help` for every built-in command +- `dotnet --cli-schema` +- `dotnet sln list`, `dotnet sln migrate`, `dotnet sln remove` + +Tool and external-command invocations (global tools, PATH commands, app-base commands) now resolve and launch out-of-process from the AOT path as well, skipping the 600–700 ms managed CLI startup for commands like `dotnet ef` or `dotnet dev-certs`. + +OpenTelemetry tracing spans are emitted from the AOT path with correct parent/child relationships to the managed CLI spans, enabling end-to-end distributed trace analysis across both hosts. ### Partial Ready-to-Run for upstack tooling A new MSBuild property lets upstack tooling (for example, `dotnet/macios` and `dotnet/maui`) declare a list of assemblies to be partially R2R-compiled and excluded from the composite image. The motivating scenario is precompiling generated XAML code in Debug builds to speed up F5 without paying the full crossgen cost for the rest of the app. App developers don't set this property directly—it's a hook the mobile workloads use in their targets. +## Test improvements + +- [dotnet test improvements](#dotnet-test-improvements) +- [Test templates support xUnit v3 and NUnit on Microsoft.Testing.Platform](#test-templates-support-xunit-v3-and-nunit-on-microsofttestingplatform) + +### dotnet test improvements + +Preview 6 adds several capabilities to `dotnet test` when running through Microsoft Testing Platform (MTP): + +- **`--no-dependencies`**: Skips building project-to-project references, matching the existing `dotnet build --no-dependencies` behavior. +- **`DOTNET_TEST_RUNNER` environment variable**: Selects the test runner without requiring a `global.json` change. Set it to `VSTest` or `Microsoft.Testing.Platform` to override `global.json` for the current session. +- **`--use-current-runtime` / `--ucr`**: Targets the current runtime during restore and build, matching the option already available on `dotnet build` and `dotnet publish`. +- **`--test-modules` exclusion patterns**: Patterns starting with `!` are now treated as excludes, and whitespace between semicolons is trimmed, making YAML-folded CI expressions work correctly. +- **Per-assembly test counts**: The summary line for multi-assembly runs now includes per-assembly counts. +- **Terminal logger arguments**: `--tl`, `--terminallogger`, and `--tlp` are now forwarded to MSBuild instead of being passed as test application arguments. +- **Live display of in-flight tests**: The progress area shows tests that are running, using a new `TestInProgressMessages` IPC event. The panel keeps per-assembly trimming for large parallel runs and is enabled only for interactive ANSI terminals. +- **Two-stage Ctrl+C cancellation**: The first press stops scheduling new test apps and shows a hint; the second press force-kills all child test processes. +- **`--device` for MAUI**: Select a device per target framework when running tests for .NET MAUI projects. +- **Protocol 1.1.0 output forwarding**: When the test host supports protocol 1.1.0, stdout/stderr and `IOutputDevice` messages are streamed live through the terminal reporter instead of being shown only on failure. + +### Test templates support xUnit v3 and NUnit on Microsoft.Testing.Platform + +The built-in `xunit` template adds a `--xunit-version` option. Use `v3` to generate an xUnit v3 project that defaults to Microsoft.Testing.Platform as the runner: + +```bash +dotnet new xunit --xunit-version v3 +dotnet new xunit --xunit-version v3 --test-runner VSTest +``` + +The `nunit` template similarly adds a `--test-runner` option to opt in to Microsoft.Testing.Platform: + +```bash +dotnet new nunit --test-runner Microsoft.Testing.Platform +``` + +Both options are available for C#, F#, and VB templates. + +## Container and tooling updates + +- [Multi-arch container builds with Podman](#multi-arch-container-builds-with-podman) +- [TypeScript outputs integrate with Static Web Assets](#typescript-outputs-integrate-with-static-web-assets) +- [MSBuild server and OpenTelemetry environment variables](#msbuild-server-and-opentelemetry-environment-variables) + +### Multi-arch container builds with Podman + +The SDK's built-in container publishing now supports building multi-architecture container images when using Podman as the container engine. Previously, multi-arch builds required Docker. This unblocks rootless multi-arch workflows on Linux distributions that ship Podman by default. + +### TypeScript outputs integrate with Static Web Assets + +Projects that use `Microsoft.TypeScript.MSBuild` in Razor Class Libraries now properly integrate TypeScript compilation outputs with ASP.NET Core Static Web Assets. The new integration hooks TypeScript outputs into the Static Web Assets pipeline after compilation, enabling compression, fingerprinting, and correct rebuild behavior. Previously, rebuild operations could fail because TypeScript outputs were discovered before compilation or stale references persisted after clean. + +### MSBuild server and OpenTelemetry environment variables + +The `dotnet` CLI no longer suppresses the MSBuild build server when `DOTNET_CLI_USE_MSBUILD_SERVER` is unset. Previously the CLI unconditionally wrote `MSBUILDUSESERVER=0`, overriding any user-set value. Now, if `DOTNET_CLI_USE_MSBUILD_SERVER` is not set, the CLI leaves `MSBUILDUSESERVER` untouched so you can enable the MSBuild server directly. + +The OTLP telemetry exporter is now also enabled when any standard OpenTelemetry `OTEL_EXPORTER_OTLP_*` environment variable is present (endpoint, protocol, headers, or timeout—including signal-specific `_TRACES_*` and `_METRICS_*` variants), in addition to the existing `DOTNET_CLI_TELEMETRY_ENABLE_EXPORTER` flag. + +## Include DLLs in file-based apps + +File-based apps can now include compiled DLL references using `#:include` without a feature flag. The default item-type mapping treats `.dll` files as `Reference` items, so you can reference prebuilt libraries directly: + +```csharp +#:include ./libs/MyLibrary.dll + +MyLibrary.Helper.DoWork(); +``` + +Additionally, more `#:` directives are now allowed to appear as duplicates across included files when their values match (`#:sdk`, `#:property`, `#:package`), enabling self-contained library files that declare their own dependencies without conflicting when multiple entry points include them. + ## See also - [What's new in the .NET 11 runtime](runtime.md) diff --git a/docs/csharp/fundamentals/statements/iteration.md b/docs/csharp/fundamentals/statements/iteration.md new file mode 100644 index 0000000000000..d598589830365 --- /dev/null +++ b/docs/csharp/fundamentals/statements/iteration.md @@ -0,0 +1,76 @@ +--- +title: "Iteration statements in C#" +description: Use foreach, while, do-while, and for to repeat a block of code, and use break and continue to control the flow of a loop. +ms.date: 07/09/2026 +ms.topic: concept-article +ai-usage: ai-assisted +--- + +# Iteration statements + +> [!TIP] +> This article is part of the **Fundamentals** section for developers who already know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. For the complete syntax, see [iteration statements](../../language-reference/statements/iteration-statements.md) in the language reference. +> +> **Coming from another language?** All four C# loops (`foreach`, `while`, `do`-`while`, and `for`) have direct equivalents in Java, C++, and JavaScript. You use `foreach` most often. It iterates a collection without an index, like Java's enhanced `for` or JavaScript's `for...of`. + +Iteration statements run a block of code repeatedly. Each pass through the block is an *iteration*, and a repeating block is a *loop*. C# provides four loops. Start with `foreach` for collections, use `while` and `do`-`while` when a condition controls the repetition, and use `for` when you need an explicit index. + +## Iterate a collection with `foreach` + +The `foreach` statement runs its body once for each element in a collection, in order. It's the most common choice for reading a collection because you don't manage an index or a bounds check. The `foreach` statement prevents typical off-by-one errors: + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="Foreach"::: + +`foreach` works with any type that C# recognizes as a sequence, including arrays, , and . The iteration variable (`name` in the previous example) is read-only, so you can't reassign it inside the loop. + +The body of a loop is a single *statement*, such as an assignment or a method call. A *block statement* is itself a single statement that encloses zero or more statements in braces (`{ }`). + +Many coding standards recommend that you enclose the loop body in braces, even for a single statement. Braces make the scope explicit. It prevents a common mistake: adding a second line later that you expect to run each iteration, but that runs once after the loop instead. Only the braces decide which statements belong to the loop. C# doesn't treat whitespace as significant, so indentation alone never does. Braces are legal even around one line: the block is the single statement that the loop repeats. Indent your code for readability, but rely on braces to define the block. + +## Repeat while a condition holds with `while` + +A `while` loop checks its Boolean condition *before* each iteration. If the condition is `false` at the start, the body never runs, so a `while` loop runs zero or more times: + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="While"::: + +Make sure something inside the loop changes the condition. In the previous example, `countdown--` eventually makes the condition `false`. A loop whose condition never becomes `false` runs forever. + +## Run the body at least once with `do`-`while` + +A `do`-`while` loop checks its condition *after* each iteration, so the body always runs at least once. Use it when the first pass must happen before you can evaluate the condition, such as prompting for input and then validating it: + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="DoWhile"::: + +## Count with `for` + +A `for` loop statement contains three parts: an *initializer* that runs once before the loop, a *condition* that's checked before each iteration, and an *iterator* that runs after each iteration. Use `for` when you need the index itself, not just the elements. Typically, you need the index when you want to modify the element rather than reading its value. + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="For"::: + +When you only read the elements, when you don't use the positions or assign new values, prefer `foreach`. It states the intent more clearly and avoids index arithmetic. + +## Exit or skip with `break` and `continue` + +Two jump statements give you finer control inside any loop. The `break` statement exits the loop immediately, skipping any remaining iterations: + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="Break"::: + +The `continue` statement skips the rest of the current iteration and moves on to the next one: + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="Continue"::: + +## Iterate an asynchronous stream with `await foreach` + +An *asynchronous stream* is a reader that uses an asynchronous task to produce each next element. C# represents it with the interface. Data that arrives over time, such as pages from a web API or rows from a database, fits this model: retrieving the next element is an awaitable operation instead of an immediate return. + +To consume an asynchronous stream, put the `await` keyword before `foreach`. Each iteration awaits the next element, so the loop suspends while that element is produced instead of blocking the thread: + +:::code language="csharp" source="./snippets/iteration-statements/Program.cs" id="AwaitForeach"::: + +Asynchronous streams build on `async` and `await`. For a full walkthrough, see [Generate and consume asynchronous streams](../../asynchronous-programming/generate-consume-asynchronous-stream.md). + +## See also + +- [Selection statements](selection.md) +- [Iteration statements (language reference)](../../language-reference/statements/iteration-statements.md) +- [Generate and consume asynchronous streams](../../asynchronous-programming/generate-consume-asynchronous-stream.md) diff --git a/docs/csharp/fundamentals/statements/selection.md b/docs/csharp/fundamentals/statements/selection.md new file mode 100644 index 0000000000000..5b7a3eea967cb --- /dev/null +++ b/docs/csharp/fundamentals/statements/selection.md @@ -0,0 +1,73 @@ +--- +title: "Selection statements in C#" +description: Use if, else, and switch statements to choose which code runs based on a condition, including pattern-based case labels and when clauses. +ms.date: 07/09/2026 +ms.topic: concept-article +ai-usage: ai-assisted +--- + +# Selection statements + +> [!TIP] +> This article is part of the **Fundamentals** section for developers who already know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. For the complete syntax, see [selection statements](../../language-reference/statements/selection-statements.md) in the language reference. +> +> **Coming from another language?** C++, Java, and JavaScript all share C's heritage, so `if`, `else`, and `switch` read the same in C#. The one difference worth noting: C# forbids fall-through between nonempty `switch` cases, and each `case` label can test a *pattern* rather than only a constant. If you're coming from Python, C#'s `if`/`else if`/`else` maps to `if`/`elif`/`else`, and C#'s pattern-based `switch` is closest to Python's `match` statement. + +Selection statements choose which block of code runs based on a condition. C# provides two: `if` (with an optional `else`) for branching on a Boolean value, and `switch` for comparing one value against several cases. A *Boolean expression* is any expression that evaluates to `true` or `false`, such as the comparison `temperature >= 25`. + +## Branch with `if` and `else` + +An `if` statement runs its block only when its Boolean expression is `true`. Add an `else` block to supply the code that runs when the condition is `false`: + +:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="IfElse"::: + +The body of an `if` or `else` is a single *statement*, such as an assignment or a method call. A *block statement* is itself a single statement that encloses zero or more statements in braces (`{ }`). + +Many coding standards recommend that you enclose the branch bodies in braces, even for a single statement. Braces make the scope explicit. It prevents a common mistake: adding a second line later that you expect to run conditionally, but that runs unconditionally instead. Only the braces decide which statements belong to the branch. C# doesn't treat whitespace as significant, so indentation alone never does. Braces are legal even around one line: the block is the single statement that the branch runs. Indent your code for readability, but rely on braces to define the block. + +## Test several conditions with `else if` + +To choose among more than two paths, chain conditions with `else if`. C# evaluates each condition in order and runs the first block whose condition is `true`, then skips the rest. A final `else` handles every remaining case: + +:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="ElseIf"::: + +Order matters in a chain. Because the first matching condition wins, put the most specific conditions first. In the previous example, testing `score >= 80` before `score >= 70` ensures a score of 82 maps to `"B"` rather than `"C"`. + +## Match a value with a `switch` statement + +When you compare a single value against many discrete cases, a `switch` statement reads more clearly than a long `else if` chain. Like `if`, the `switch` statement is a branching statement: it chooses which code to run. Each `case` label lists a value to match, and each `case` section ends with a `break` statement. Stack labels to share one body, and use the `default` section for values that no case matches: + +:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="SwitchStatement"::: + +Unlike C and Java, C# doesn't allow execution to fall through from one nonempty `case` section into the next. Every section that contains code must end with a `break` (or another jump statement, such as `return` or `goto`). This rule prevents the accidental fall-through bugs common in those languages. + +### Test patterns with `case` and `when` + +A `case` label isn't limited to constant values. It can test a *pattern*, which is a rule that describes the shape or value of data. A relational pattern such as `< 0` matches any value less than zero. Add a `when` clause to attach an extra condition that must also be `true` for the case to match: + +:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="SwitchWhen"::: + +Pattern-based cases are evaluated top to bottom, so more specific patterns belong before more general ones. For the full catalog of patterns, see [pattern matching](../functional/pattern-matching.md). + +## Select a value with an expression + +The `if` and `switch` statements decide which code runs. When you instead need to choose a *value*, use an *expression*. An expression evaluates to a value, so you can use it anywhere a value is expected, such as the right side of an assignment or a method argument. C# offers expression forms that select a value from alternatives such as the conditional operator and the `switch` expression. + +### Conditional operator `?:` + +The conditional operator `?:` chooses between two values based on a Boolean condition. It takes the form `condition ? valueIfTrue : valueIfFalse`: + +:::code language="csharp" source="./snippets/selection-statements/Program.cs" id="Ternary"::: + +Use `?:` when you assign one of two values, because it keeps the assignment in one place and lets you mark the variable `readonly` or `const`. Prefer an `if` statement when the branches do more than produce a value. For the operator's precedence and associativity rules, see the [conditional operator](../../language-reference/operators/conditional-operator.md) in the language reference. + +### `switch` expression + +A `switch` expression is the expression counterpart to the `switch` statement. Instead of running code for the matching case, it evaluates to a value. It's more concise than assigning a value in each arm of a `switch` statement, and the compiler warns you when the arms don't cover every possible input. The `switch` expression is a core part of pattern matching. To learn when and how to use it, see [pattern matching](../functional/pattern-matching.md) and the [`switch` expression](../../language-reference/operators/switch-expression.md) reference. + +## See also + +- [Iteration statements](iteration.md) +- [Pattern matching](../functional/pattern-matching.md) +- [Selection statements (language reference)](../../language-reference/statements/selection-statements.md) +- [Conditional operator (language reference)](../../language-reference/operators/conditional-operator.md) diff --git a/docs/csharp/fundamentals/statements/snippets/iteration-statements/Program.cs b/docs/csharp/fundamentals/statements/snippets/iteration-statements/Program.cs new file mode 100644 index 0000000000000..9c4e8db5f74a9 --- /dev/null +++ b/docs/csharp/fundamentals/statements/snippets/iteration-statements/Program.cs @@ -0,0 +1,128 @@ +namespace IterationStatements; + +public static class Program +{ + public static async Task Main() + { + ForeachExample(); + WhileExample(); + DoWhileExample(); + ForExample(); + BreakExample(); + ContinueExample(); + await AwaitForeachExample(); + } + + private static void ForeachExample() + { + // + string[] names = ["Ana", "Ben", "Cleo"]; + + // foreach reads each element in order. It's the default loop for + // collections: no index to manage and no off-by-one mistakes. + foreach (string name in names) + { + Console.WriteLine(name); // => Ana, then Ben, then Cleo + } + // + } + + private static void WhileExample() + { + // + int countdown = 3; + + // A while loop checks its condition before each iteration, so the body + // runs zero or more times. + while (countdown > 0) + { + Console.WriteLine(countdown); // => 3, then 2, then 1 + countdown--; + } + // + } + + private static void DoWhileExample() + { + // + int attempts = 0; + + // A do-while loop runs its body once, then checks the condition. Use it + // when the body must run at least one time. + do + { + attempts++; + Console.WriteLine($"Attempt {attempts}"); // => Attempt 1, then Attempt 2, then Attempt 3 + } + while (attempts < 3); + // + } + + private static void ForExample() + { + // + // A for loop fits when you need an explicit index. The three parts are + // the initializer, the condition, and the iterator. + for (int i = 0; i < 3; i++) + { + Console.WriteLine(i); // => 0, then 1, then 2 + } + // + } + + private static void BreakExample() + { + // + int[] numbers = [2, 4, 7, 8]; + + // break stops the loop immediately, skipping any remaining elements. + foreach (int number in numbers) + { + if (number % 2 != 0) + { + Console.WriteLine($"First odd number: {number}"); // => First odd number: 7 + break; + } + } + // + } + + private static void ContinueExample() + { + // + int[] values = [1, 2, 3, 4, 5]; + + // continue skips the rest of the current iteration and moves to the next. + foreach (int value in values) + { + if (value % 2 == 0) + { + continue; // skip even numbers + } + + Console.WriteLine(value); // => 1, then 3, then 5 + } + // + } + + // + private static async Task AwaitForeachExample() + { + // await foreach consumes an asynchronous stream. Each iteration can + // suspend while the next element is produced. + await foreach (int value in GenerateAsync()) + { + Console.WriteLine(value); // => 0, then 1, then 2 + } + } + + private static async IAsyncEnumerable GenerateAsync() + { + for (int i = 0; i < 3; i++) + { + await Task.Delay(1); // stand-in for real asynchronous work + yield return i; + } + } + // +} diff --git a/docs/csharp/fundamentals/statements/snippets/iteration-statements/iteration-statements.csproj b/docs/csharp/fundamentals/statements/snippets/iteration-statements/iteration-statements.csproj new file mode 100644 index 0000000000000..bad583f080c8c --- /dev/null +++ b/docs/csharp/fundamentals/statements/snippets/iteration-statements/iteration-statements.csproj @@ -0,0 +1,8 @@ + + + Exe + net10.0 + enable + enable + + diff --git a/docs/csharp/fundamentals/statements/snippets/selection-statements/Program.cs b/docs/csharp/fundamentals/statements/snippets/selection-statements/Program.cs new file mode 100644 index 0000000000000..f0c087ac20662 --- /dev/null +++ b/docs/csharp/fundamentals/statements/snippets/selection-statements/Program.cs @@ -0,0 +1,119 @@ +namespace SelectionStatements; + +public static class Program +{ + public static void Main() + { + IfElseExample(); + ElseIfExample(); + SwitchStatementExample(); + SwitchWhenExample(); + TernaryExample(); + } + + private static void IfElseExample() + { + // + int temperature = 28; + + // An if statement runs its block only when the condition is true. + // The else block runs when the condition is false. + if (temperature >= 25) + { + Console.WriteLine("Warm"); // => Warm + } + else + { + Console.WriteLine("Cool"); + } + // + } + + private static void ElseIfExample() + { + // + int score = 82; + + // Chain conditions with else if. The first branch whose condition is + // true runs; the compiler skips the rest. + string grade; + if (score >= 90) + { + grade = "A"; + } + else if (score >= 80) + { + grade = "B"; + } + else if (score >= 70) + { + grade = "C"; + } + else + { + grade = "F"; + } + + Console.WriteLine(grade); // => B + // + } + + private static void SwitchStatementExample() + { + // + DayOfWeek day = DayOfWeek.Saturday; + + // A switch statement compares one value against several case labels. + // Stacked labels share a body. Each section ends with break, and the + // default section runs when no case matches. + switch (day) + { + case DayOfWeek.Saturday: + case DayOfWeek.Sunday: + Console.WriteLine("Weekend"); // => Weekend + break; + default: + Console.WriteLine("Weekday"); + break; + } + // + } + + private static void SwitchWhenExample() + { + // + int measurement = 42; + + // A case label can test a pattern instead of a constant. A when clause + // adds a condition that must also be true for the case to match. + switch (measurement) + { + case < 0: + Console.WriteLine("Negative"); + break; + case 0: + Console.WriteLine("Zero"); + break; + case > 0 when measurement % 2 == 0: + Console.WriteLine("Positive and even"); // => Positive and even + break; + default: + Console.WriteLine("Positive and odd"); + break; + } + // + } + + private static void TernaryExample() + { + // + int hour = 9; + + // The conditional operator ?: chooses between two values in a single + // expression: condition ? valueIfTrue : valueIfFalse. + string greeting = hour < 12 ? "Good morning" : "Good afternoon"; + + Console.WriteLine(greeting); // => Good morning + // + } +} diff --git a/docs/csharp/fundamentals/statements/snippets/selection-statements/selection-statements.csproj b/docs/csharp/fundamentals/statements/snippets/selection-statements/selection-statements.csproj new file mode 100644 index 0000000000000..bad583f080c8c --- /dev/null +++ b/docs/csharp/fundamentals/statements/snippets/selection-statements/selection-statements.csproj @@ -0,0 +1,8 @@ + + + Exe + net10.0 + enable + enable + + diff --git a/docs/csharp/language-reference/builtin-types/numeric-conversions.md b/docs/csharp/language-reference/builtin-types/numeric-conversions.md index 0ebb39a345c63..722996b7379ed 100644 --- a/docs/csharp/language-reference/builtin-types/numeric-conversions.md +++ b/docs/csharp/language-reference/builtin-types/numeric-conversions.md @@ -22,17 +22,17 @@ The following table shows the predefined implicit conversions between the built- | From | To | |------------------------------------------|--------| -| [sbyte](integral-numeric-types.md) | `short`, `int`, `long`, `float`, `double`, `decimal`, or `nint` | -| [byte](integral-numeric-types.md) | `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `nint`, or `nuint` | -| [short](integral-numeric-types.md) | `int`, `long`, `float`, `double`, `decimal`, or `nint` | -| [ushort](integral-numeric-types.md) | `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `nint`, or `nuint` | -| [int](integral-numeric-types.md) | `long`, `float`, `double`, `decimal`, or `nint` | -| [uint](integral-numeric-types.md) | `long`, `ulong`, `float`, `double`, `decimal`, or `nuint` | -| [long](integral-numeric-types.md) | `float`, `double`, or `decimal` | -| [ulong](integral-numeric-types.md) | `float`, `double`, or `decimal` | -| [float](floating-point-numeric-types.md) | `double` | -| [nint](integral-numeric-types.md) | `long`, `float`, `double`, or `decimal` | -| [nuint](integral-numeric-types.md) | `ulong`, `float`, `double`, or `decimal` | +| [`sbyte`](integral-numeric-types.md) | `short`, `int`, `long`, `float`, `double`, `decimal`, or `nint` | +| [`byte`](integral-numeric-types.md) | `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `nint`, or `nuint` | +| [`short`](integral-numeric-types.md) | `int`, `long`, `float`, `double`, `decimal`, or `nint` | +| [`ushort`](integral-numeric-types.md) | `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `nint`, or `nuint` | +| [`int`](integral-numeric-types.md) | `long`, `float`, `double`, `decimal`, or `nint` | +| [`uint`](integral-numeric-types.md) | `long`, `ulong`, `float`, `double`, `decimal`, or `nuint` | +| [`long`](integral-numeric-types.md) | `float`, `double`, or `decimal` | +| [`ulong`](integral-numeric-types.md) | `float`, `double`, or `decimal` | +| [`float`](floating-point-numeric-types.md) | `double` | +| [`nint`](integral-numeric-types.md) | `long`, `float`, `double`, or `decimal` | +| [`nuint`](integral-numeric-types.md) | `ulong`, `float`, `double`, or `decimal` | > [!NOTE] > The implicit conversions from `int`, `uint`, `long`, `ulong`, `nint`, or `nuint` to `float` and from `long`, `ulong`, `nint`, or `nuint` to `double` can cause a loss of precision, but never a loss of an order of magnitude. The other implicit numeric conversions never lose any information. diff --git a/docs/csharp/language-reference/compiler-messages/cs0446.md b/docs/csharp/language-reference/compiler-messages/cs0446.md deleted file mode 100644 index 8291d78372202..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs0446.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: "Compiler Error CS0446" -title: "Compiler Error CS0446" -ms.date: 07/20/2015 -f1_keywords: - - "CS0446" -helpviewer_keywords: - - "CS0446" -ms.assetid: d7a07e24-722e-484d-b6d7-ca809b51858f ---- -# Compiler Error CS0446 - -Foreach cannot operate on a 'Method or Delegate'. Did you intend to invoke the 'Method or Delegate'? - - This error is caused by specifying a method without parentheses or an anonymous method without parentheses in the part of the `foreach` statement where you would normally put a collection class. Note that it is valid, though unusual, to put a method call in that location, if the method returns a collection class. - -## Example - - The following code will generate CS0446. - -```csharp -// CS0446.cs -using System; -class Tester -{ - static void Main() - { - int[] intArray = new int[5]; - foreach (int i in M) { } // CS0446 - } - static void M() { } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/cs1579.md b/docs/csharp/language-reference/compiler-messages/cs1579.md deleted file mode 100644 index 07814fab8df20..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs1579.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -description: "Compiler Error CS1579" -title: "Compiler Error CS1579" -ms.date: 05/24/2018 -f1_keywords: - - "CS1579" -helpviewer_keywords: - - "CS1579" -ms.assetid: 1eba84ce-58df-4fe3-9134-e26efefdc4ab ---- -# Compiler Error CS1579 - -foreach statement cannot operate on variables of type 'type1' because 'type2' does not contain a public definition for 'identifier' - -To iterate through a collection using the [foreach](../statements/iteration-statements.md#the-foreach-statement) statement, the collection must meet the following requirements: - -- Its type must include a public parameterless `GetEnumerator` method whose return type is either class, struct, or interface type. -- The return type of the `GetEnumerator` method must contain a public property named `Current` and a public parameterless method named `MoveNext` whose return type is . - -## Example - -The following sample generates CS1579 because the `MyCollection` class doesn't contain the public `GetEnumerator` method: - -```csharp -// CS1579.cs -using System; -public class MyCollection -{ - int[] items; - public MyCollection() - { - items = new int[5] {12, 44, 33, 2, 50}; - } - - // Delete the following line to resolve. - MyEnumerator GetEnumerator() - - // Uncomment the following line to resolve: - // public MyEnumerator GetEnumerator() - { - return new MyEnumerator(this); - } - - // Declare the enumerator class: - public class MyEnumerator - { - int nIndex; - MyCollection collection; - public MyEnumerator(MyCollection coll) - { - collection = coll; - nIndex = -1; - } - - public bool MoveNext() - { - nIndex++; - return (nIndex < collection.items.Length); - } - - public int Current => collection.items[nIndex]; - } - - public static void Main() - { - MyCollection col = new MyCollection(); - Console.WriteLine("Values in the collection are:"); - foreach (int i in col) // CS1579 - { - Console.WriteLine(i); - } - } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/cs1640.md b/docs/csharp/language-reference/compiler-messages/cs1640.md deleted file mode 100644 index e8132b01560cb..0000000000000 --- a/docs/csharp/language-reference/compiler-messages/cs1640.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -description: "Compiler Error CS1640" -title: "Compiler Error CS1640" -ms.date: 07/20/2015 -f1_keywords: - - "CS1640" -helpviewer_keywords: - - "CS1640" -ms.assetid: 1393668e-05e9-4dc2-9203-3d9c2933406f ---- -# Compiler Error CS1640 - -foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface', try casting to a specific interface instantiation - - The type inherits from two or more instances of IEnumerator\, which means there is not a unique enumeration of the type that `foreach` could use. Specify the type of IEnumerator\ or use another looping construct. - -## Example - - The following sample generates CS1640: - -```csharp -// CS1640.cs - -using System; -using System.Collections; -using System.Collections.Generic; - -public class C : IEnumerable, IEnumerable, IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield break; - } - - IEnumerator IEnumerable.GetEnumerator() - { - yield break; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return (IEnumerator)((IEnumerable)this).GetEnumerator(); - } -} - -public class Test -{ - public static int Main() - { - foreach (int i in new C()){} // CS1640 - - // Try specifying the type of IEnumerable - // foreach (int i in (IEnumerable)new C()){} - return 1; - } -} -``` diff --git a/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md new file mode 100644 index 0000000000000..b09f32813c884 --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/foreach-diagnostics.md @@ -0,0 +1,159 @@ +--- +title: "Resolve errors and warnings related to async enumerables, enumerables, and `foreach` statements" +description: "This article helps you diagnose and correct compiler errors and warnings related to async enumerables, enumerables, and foreach statements" +f1_keywords: + - "CS0202" + - "CS0230" + - "CS0278" + - "CS0279" + - "CS0280" + - "CS0446" + - "CS1579" + - "CS1640" + - "CS8186" + - "CS8412" + - "CS8413" + - "CS8414" + - "CS8415" + - "CS8419" + - "CS8420" + - "CS8424" + - "CS8425" + - "CS8426" + - "CS9353" +helpviewer_keywords: + - "CS0202" + - "CS0230" + - "CS0278" + - "CS0279" + - "CS0280" + - "CS0446" + - "CS1579" + - "CS1640" + - "CS8186" + - "CS8412" + - "CS8413" + - "CS8414" + - "CS8415" + - "CS8419" + - "CS8420" + - "CS8424" + - "CS8425" + - "CS8426" + - "CS9353" +ms.date: 07/13/2026 +ai-usage: ai-assisted +--- + +# Resolve errors and warnings for `foreach` statements and async enumerables + +This article covers the following compiler errors and warnings: + + + +- [**CS0202**](#enumerable-pattern-requirements): *foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property* +- [**CS0230**](#foreach-statement-syntax): *Type and identifier are both required in a foreach statement* +- [**CS0278**](#enumerable-pattern-requirements): *'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'.* +- [**CS0279**](#enumerable-pattern-requirements): *'type' does not implement the 'pattern name' pattern. 'method name' is not a public instance or extension method.* +- [**CS0280**](#enumerable-pattern-requirements): *'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature.* +- [**CS0446**](#foreach-statement-syntax): *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* +- [**CS1579**](#enumerable-pattern-requirements): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* +- [**CS1640**](#multiple-enumerable-implementations): *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- [**CS8186**](#foreach-statement-syntax): *A foreach loop must declare its iteration variables.* +- [**CS8412**](#enumerable-pattern-requirements): *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* +- [**CS8413**](#multiple-enumerable-implementations): *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- [**CS8414**](#mismatched-foreach-and-await-foreach): *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* +- [**CS8415**](#mismatched-foreach-and-await-foreach): *Asynchronous foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'foreach' rather than 'await foreach'?* +- [**CS8419**](#async-iterator-method-body): *The body of an async-iterator method must contain a 'yield' statement.* +- [**CS8420**](#async-iterator-method-body): *The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.* +- [**CS8424**](#enumeratorcancellation-attribute-usage): *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* +- [**CS8425**](#enumeratorcancellation-attribute-usage): *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* +- [**CS8426**](#enumeratorcancellation-attribute-usage): *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* +- [**CS9353**](#mismatched-foreach-and-await-foreach): *'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?)* + +## `foreach` statement syntax + +- **CS0230**: *Type and identifier are both required in a foreach statement* +- **CS0446**: *Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'?* +- **CS8186**: *A foreach loop must declare its iteration variables.* + +These errors indicate that the [`foreach` statement](../statements/iteration-statements.md#the-foreach-statement) itself is malformed, regardless of whether the collection type is valid. + +Declare both a type (or `var`) and an identifier for the iteration variable (**CS0230**, **CS8186**). The `foreach` statement requires a loop variable declaration. You can't omit either the type or the name. For example, write `foreach (int x in collection)` rather than `foreach (int in collection)`. + +Invoke the method or delegate rather than passing it as a collection expression (**CS0446**). If you reference a method group or delegate without parentheses in the `in` clause, the compiler reports this error because it expects a collection value. Add parentheses to call the method, provided it returns an enumerable type: `foreach (var item in GetItems())`. + +## Enumerable pattern requirements + +- **CS0202**: *foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public 'MoveNext' method and public 'Current' property* +- **CS0278**: *'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'.* +- **CS0279**: *'type' does not implement the 'pattern name' pattern. 'method name' is not a public instance or extension method.* +- **CS0280**: *'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature.* +- **CS1579**: *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'* +- **CS8412**: *Asynchronous foreach requires that the return type 'type' of 'method' must have a suitable public 'MoveNextAsync' method and public 'Current' property* + +The `foreach` statement uses a pattern-based approach rather than requiring a specific interface. For a type to be enumerable, it must provide: + +- A public parameterless `GetEnumerator` method (or `GetAsyncEnumerator` for `await foreach`) whose return type is a class, struct, or interface. +- On the enumerator return type: a public `Current` property and a public parameterless `MoveNext` method returning `bool` (or a public parameterless `MoveNextAsync` method that returns `Task`, `ValueTask`, or any other awaitable type whose awaiter's `GetResult` method returns a `bool` value). +For details on the enumerable pattern, see [Iteration statements - `foreach`](../statements/iteration-statements.md#the-foreach-statement). + +Ensure `GetEnumerator` returns a proper enumerator type — not an array or pointer (**CS0202**). The return value must be a type that itself exposes `MoveNext` and `Current`. + +Add a public `GetEnumerator` method if the type doesn't have one (**CS1579**). Alternatively, implement or provide an extension method named `GetEnumerator`. For `await foreach`, provide `GetAsyncEnumerator` or implement . + +Ensure that `GetAsyncEnumerator` returns a type with a public `Current` property and a public parameterless `MoveNextAsync` method that returns `Task`, `ValueTask`, or any other awaitable type whose awaiter's `GetResult` method returns a `bool` value (**CS8412**). This is the async equivalent of **CS0202**. + +Resolve ambiguity when multiple methods match the pattern name (**CS0278**). This warning occurs when the compiler finds two candidates for `MoveNext` or `GetEnumerator`. Remove or rename the conflicting member, or cast to a specific interface to disambiguate. + +Make pattern methods public and non-static (**CS0279**). The enumerable pattern requires that `GetEnumerator`, `MoveNext`, and `Current` be public instance members (or public extension methods). Change `internal` or `static` members to `public` instance members. + +Correct the signature of pattern methods (**CS0280**). For example, `MoveNext` must take no parameters and return `bool`. If a field or property shadows the method name, rename it so the compiler can find the correct method. + +## Multiple enumerable implementations + +- **CS1640**: *foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* +- **CS8413**: *Asynchronous foreach statement cannot operate on variables of type 'type' because it implements multiple instantiations of 'interface'; try casting to a specific interface instantiation* + +These errors occur when the collection type implements multiple generic instantiations of (**CS1640**) or (**CS8413**), creating ambiguity about which element type to enumerate. + +Cast the collection to a specific interface instantiation before iterating. For example, if a type implements both `IEnumerable` and `IEnumerable`, write `foreach (int i in (IEnumerable)collection)` to select the desired element type. + +## Mismatched `foreach` and `await foreach` + +- **CS8414**: *foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'await foreach' rather than 'foreach'?* +- **CS8415**: *Asynchronous foreach statement cannot operate on variables of type 'type' because 'type' does not contain a public instance or extension definition for 'member'. Did you mean 'foreach' rather than 'await foreach'?* +- **CS9353**: *'type' does not contain a definition for 'member' and no accessible extension method 'member' accepting a first argument of type 'type' could be found (did you mean to iterate over the async collection with 'await foreach' instead?)* + +These errors indicate a mismatch between the kind of `foreach` statement and the interfaces the collection type implements. + +Use `await foreach` instead of `foreach` when the collection implements only (**CS8414**, **CS9353**). Async-enumerable types provide `GetAsyncEnumerator` rather than `GetEnumerator`, so you must use `await foreach` in an `async` method to iterate them. + +Use `foreach` instead of `await foreach` when the collection implements only (**CS8415**). Synchronous collections don't provide `GetAsyncEnumerator`, so `await foreach` can't enumerate them. + +## Async iterator method body + +- **CS8419**: *The body of an async-iterator method must contain a 'yield' statement.* +- **CS8420**: *The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement.* + +These errors occur when a method's signature declares it as an async iterator (it's `async` and returns or ) but the body contains no `yield return` or `yield break` statement. + +Add at least one `yield return` statement to the method body to make it a valid async-iterator method. If you didn't intend the method to be an iterator, remove the `async` modifier and change the return type, or return a constructed async enumerable from a different source instead. + +For more information on iterator methods, see [Iterators](../../iterators.md) and [`yield` statement](../statements/yield.md). + +## `EnumeratorCancellation` attribute usage + +- **CS8424**: *The EnumeratorCancellationAttribute applied to parameter 'name' will have no effect. The attribute is only effective on a parameter of type CancellationToken in an async-iterator method returning IAsyncEnumerable* +- **CS8425**: *Async-iterator 'method' has one or more parameters of type 'CancellationToken' but none of them is decorated with the 'EnumeratorCancellation' attribute, so the cancellation token parameter from the generated 'IAsyncEnumerable<>.GetAsyncEnumerator' will be unconsumed* +- **CS8426**: *The attribute [EnumeratorCancellation] cannot be used on multiple parameters* + +These diagnostics relate to the , which connects a parameter to the token supplied by . + +Apply `[EnumeratorCancellation]` only to a parameter of type in an async-iterator method that returns (**CS8424**). The attribute has no effect in any other context, such as non-token parameters, non-iterator methods, or methods returning other types. + +Add the `[EnumeratorCancellation]` attribute to exactly one `CancellationToken` parameter (**CS8425**). Without this attribute, the token provided by callers through `WithCancellation` isn't forwarded to the iterator body. The generated `GetAsyncEnumerator(CancellationToken)` parameter goes unconsumed. + +Apply the attribute to only one parameter, not multiple (**CS8426**). The runtime infrastructure supports forwarding a single cancellation token to the iterator. If you have multiple token parameters, designate only one with the attribute and combine others manually using . diff --git a/docs/csharp/language-reference/keywords/extension.md b/docs/csharp/language-reference/keywords/extension.md index 5b3c2f395e4e3..741cdfeec25c4 100644 --- a/docs/csharp/language-reference/keywords/extension.md +++ b/docs/csharp/language-reference/keywords/extension.md @@ -1,7 +1,7 @@ --- title: "Extension member declarations" description: "Learn the syntax to declare extension members in C#. Extension members enable you to add functionality to types and interfaces in those instances where you don't have the source for the original type. Extensions are often paired with generic interfaces to implement a common set of functionality across all types that implement that interface." -ms.date: 01/21/2026 +ms.date: 07/08/2026 f1_keywords: - "extension_CSharpKeyword" - "extension" @@ -12,7 +12,7 @@ Starting with C# 14, top-level, nongeneric `static class` declarations can use ` [!INCLUDE[csharp-version-note](../includes/initial-version.md)] -The `extension` block specifies the type and receiver for extension members. You can declare methods, properties, or operators inside the `extension` declaration. The following example declares a single extension block that defines an instance extension method, an instance property, and a static operator method. +The `extension` block specifies the type and receiver for extension members. You can declare methods, properties, indexers, and operators inside the `extension` declaration. The following example declares a single extension block that defines an instance extension method, an instance property, and a static operator method. > [!NOTE] > All the examples in this article include XML comments for the members and the extension block. The node on the `extension` block describes the extended type and the receiver parameter. The C# compiler copies this node to the generated member for all members in the extension block. These examples demonstrate the preferred style for generating XML documentation for extension members. @@ -66,9 +66,22 @@ The equivalent extension method declarations demonstrate how those type paramete :::code language="csharp" source="./snippets/ExtensionMethods.cs" id="GenericExtensionMethods"::: +## Extension indexers + +Starting with C# 15, you can declare *indexers* in an `extension` block. An extension indexer lets you index into a receiver as though the indexer were declared on the receiver type. Because indexers are always instance members, an extension block that declares an indexer must provide a named receiver parameter. Extension indexers support the same features as ordinary indexers, including `get` and `set` accessors, expression-bodied accessors, and ref-returning accessors. + +The following example declares a get-only indexer on `IEnumerable` that returns the element at a specified position: + +:::code language="csharp" source="./snippets/extensions.cs" id="ExtensionIndexer"::: + +You index into the receiver as though the indexer were a member of the receiver type: + +:::code language="csharp" source="./snippets/extensions.cs" id="UseExtensionIndexer"::: + ## See also - [Extensions feature specification](~/_csharplang/proposals/csharp-14.0/extensions.md) +- [Extension indexers feature specification](~/_csharplang/proposals/extension-indexers.md) ## C# language specification diff --git a/docs/csharp/language-reference/keywords/snippets/Extensions.cs b/docs/csharp/language-reference/keywords/snippets/Extensions.cs index b4f8ae7dadd5e..3b8343a37339d 100644 --- a/docs/csharp/language-reference/keywords/snippets/Extensions.cs +++ b/docs/csharp/language-reference/keywords/snippets/Extensions.cs @@ -202,6 +202,28 @@ public IEnumerable Prepend(IEnumerable second, Func +// +/// +/// Contains an extension indexer for numeric sequences. +/// +public static class SequenceIndexer +{ + /// + /// Defines an indexer for integer sequences. + /// + /// The sequence used as a receiver. + extension(IEnumerable sequence) + { + /// + /// Gets the element at the specified position in the sequence. + /// + /// The zero-based position of the element to retrieve. + /// The element at the specified position. + public int this[int index] => sequence.ElementAt(index); + } +} +// + public static class ExtensionExamples { public static void BasicExample() @@ -219,5 +241,9 @@ public static void BasicExample() var newSequence = IEnumerable.Generate(5, 10, 2); var identity = IEnumerable.Identity; // + + // + int third = numbers[2]; + // } } diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 5c871285af4ec..1654d4c4eb8df 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -495,13 +495,14 @@ items: - name: Feature or version missing href: ./compiler-messages/feature-version-errors.md displayName: > - CS0171, CS0188, CS0843, CS1617, CS1638, CS1738, CS8021, CS8022, CS8023, CS8024, CS8025, CS8026, - CS8058, CS8059, CS8107, CS8192, CS8302, CS8303, CS8304, CS8305, CS8306, CS8314, - CS8320, CS8370, CS8371, CS8400, CS8401, CS8511, CS8627, CS8630, CS8652, CS8701, - CS8702, CS8703, CS8704, CS8706, CS8707, CS8773, CS8830, CS8831, CS8888, CS8889, - CS8890, CS8891, CS8904, CS8912, CS8919, CS8929, CS8936, CS8957, CS8967, CS9014, - CS9015, CS9016, CS9017, CS9041, CS9058, CS9064, CS9103, CS9171, CS9194, CS9202, - CS9204, CS9240, CS9260, CS9268, CS9269, CS9271, CS9327, CS9328, CS9346, CS9352 + CS0171, CS0188, CS0843, CS1617, CS1638, CS1738, CS8021, CS8022, CS8023, CS8024, + CS8025, CS8026, CS8058, CS8059, CS8107, CS8192, CS8302, CS8303, CS8304, CS8305, + CS8306, CS8314, CS8320, CS8370, CS8371, CS8400, CS8401, CS8511, CS8627, CS8630, + CS8652, CS8701, CS8702, CS8703, CS8704, CS8706, CS8707, CS8773, CS8830, CS8831, + CS8888, CS8889, CS8890, CS8891, CS8904, CS8912, CS8919, CS8929, CS8936, CS8957, + CS8967, CS9014, CS9015, CS9016, CS9017, CS9041, CS9058, CS9064, CS9103, CS9171, + CS9194, CS9202, CS9204, CS9240, CS9260, CS9268, CS9269, CS9271, CS9327, CS9328, + CS9346, CS9352 - name: Assembly references href: ./compiler-messages/assembly-references.md displayName: > @@ -622,6 +623,12 @@ items: yield return, yield break, CS1622, CS1624, CS1625, CS1626, CS1627, CS1629, CS1631, CS1637, CS4013, CS8154, CS8176, CS9237, CS9238, CS9239 + - name: foreach statements and async enumerables + href: ./compiler-messages/foreach-diagnostics.md + displayName: > + foreach, await foreach, async enumerable, GetAsyncEnumerator, IAsyncEnumerable, + CS0202, CS0230, CS0278, CS0279, CS0280, CS0446, CS1579, CS1640, CS8186, CS8412, + CS8413, CS8414, CS8415, CS8419, CS8420, CS8424, CS8425, CS8426, CS9353 - name: Extension declarations href: ./compiler-messages/extension-declarations.md displayName: > @@ -687,11 +694,11 @@ items: - name: Lambda expressions href: ./compiler-messages/lambda-expression-errors.md displayName: > - CS0407, CS0428, CS0467, CS0748, CS0815, CS0828, CS0837, CS1065, CS1621, CS1628, CS1632, - CS1643, CS1660, CS1661, CS1662, CS1673, CS1676, CS1677, CS1678, CS1686, CS1688, - CS1706, CS1731, CS1732, CS1764, CS1911, CS1989, CS3006, CS8030, CS8175, CS8820, - CS8821, CS8916, CS8917, CS8934, CS8971, CS8972, CS8974, CS8975, CS9098, CS9099, - CS9100, CS9236 + CS0407, CS0428, CS0467, CS0748, CS0815, CS0828, CS0837, CS1065, CS1621, CS1628, + CS1632, CS1643, CS1660, CS1661, CS1662, CS1673, CS1676, CS1677, CS1678, CS1686, + CS1688, CS1706, CS1731, CS1732, CS1764, CS1911, CS1989, CS3006, CS8030, CS8175, + CS8820, CS8821, CS8916, CS8917, CS8934, CS8971, CS8972, CS8974, CS8975, CS9098, + CS9099, CS9100, CS9236 - name: Delegate and function pointer declarations href: ./compiler-messages/delegate-function-pointer-diagnostics.md displayName: > @@ -715,11 +722,11 @@ items: - name: Using directive and aliases href: ./compiler-messages/using-directive-errors.md displayName: > - CS0104, CS0105, CS0116, CS0138, CS0430, CS0431, CS0432, CS0434, CS0435, CS0436, CS0437, - CS0438, CS0439, CS0440, CS0518, CS0576, CS0687, CS1022, CS1529, - CS1537, CS1671, CS1679, CS1680, CS1681, CS1730, CS2034, CS7000, CS7007, CS7015, - CS7021, CS8019, CS8020, CS8083, CS8085, CS8914, CS8915, CS8933, CS8954, CS8955, CS8956, CS9130, - CS9131, CS9132, CS9133, CS9162 + CS0104, CS0105, CS0116, CS0138, CS0430, CS0431, CS0432, CS0434, CS0435, CS0436, + CS0437, CS0438, CS0439, CS0440, CS0518, CS0576, CS0687, CS1022, CS1529, CS1537, + CS1671, CS1679, CS1680, CS1681, CS1730, CS2034, CS7000, CS7007, CS7015, CS7021, + CS8019, CS8020, CS8083, CS8085, CS8914, CS8915, CS8933, CS8954, CS8955, CS8956, + CS9130, CS9131, CS9132, CS9133, CS9162 - name: Using statements and declarations href: ./compiler-messages/using-statement-declaration-errors.md displayName: > @@ -976,12 +983,8 @@ items: href: ../misc/cs0191.md - name: CS0198 href: ../misc/cs0198.md - - name: CS0200 - href: ./compiler-messages/property-declaration-errors.md - name: CS0201 href: ./compiler-messages/cs0201.md - - name: CS0202 - href: ../misc/cs0202.md - name: CS0204 href: ../misc/cs0204.md - name: CS0205 @@ -992,8 +995,6 @@ items: href: ../misc/cs0228.md - name: CS0229 href: ./compiler-messages/cs0229.md - - name: CS0230 - href: ../misc/cs0230.md - name: CS0236 href: ../misc/cs0236.md - name: CS0238 @@ -1042,14 +1043,10 @@ items: href: ../misc/cs0443.md - name: CS0445 href: ./compiler-messages/cs0445.md - - name: CS0446 - href: ./compiler-messages/cs0446.md - name: CS0462 href: ../misc/cs0462.md - name: CS0468 href: ../misc/cs0468.md - - name: CS0470 - href: ./compiler-messages/interface-implementation-errors.md - name: CS0471 href: ../misc/cs0471.md - name: CS0500 @@ -1092,26 +1089,14 @@ items: href: ../misc/cs0534.md - name: CS0537 href: ../misc/cs0537.md - - name: CS0538 - href: ./compiler-messages/interface-implementation-errors.md - - name: CS0539 - href: ./compiler-messages/interface-implementation-errors.md - - name: CS0541 - href: ./compiler-messages/interface-implementation-errors.md - name: CS0542 href: ../misc/cs0542.md - - name: CS0545 - href: ./compiler-messages/property-declaration-errors.md - name: CS0549 href: ../misc/cs0549.md - - name: CS0551 - href: ./compiler-messages/interface-implementation-errors.md - name: CS0569 href: ../misc/cs0569.md - name: CS0570 href: ./compiler-messages/cs0570.md - - name: CS0571 - href: ./compiler-messages/property-declaration-errors.md - name: CS0572 href: ../misc/cs0572.md - name: CS0574 @@ -1248,8 +1233,6 @@ items: href: ../misc/cs0833.md - name: CS0836 href: ../misc/cs0836.md - - name: CS0840 - href: ./compiler-messages/property-declaration-errors.md - name: CS0841 href: ../misc/cs0841.md - name: CS0842 @@ -1270,8 +1253,6 @@ items: href: ../misc/cs1010.md - name: CS1013 href: ../misc/cs1013.md - - name: CS1014 - href: ./compiler-messages/property-declaration-errors.md - name: CS1015 href: ../misc/cs1015.md - name: CS1017 @@ -1292,8 +1273,6 @@ items: href: ../misc/cs1036.md - name: CS1041 href: ../misc/cs1041.md - - name: CS1043 - href: ./compiler-messages/property-declaration-errors.md - name: CS1044 href: ../misc/cs1044.md - name: CS1055 @@ -1386,8 +1365,6 @@ items: href: ../misc/cs1575.md - name: CS1577 href: ../misc/cs1577.md - - name: CS1579 - href: ./compiler-messages/cs1579.md - name: CS1583 href: ../misc/cs1583.md - name: CS1585 @@ -1422,12 +1399,8 @@ items: href: ../misc/cs1620.md - name: CS1630 href: ../misc/cs1630.md - - name: CS1637 - href: ./compiler-messages/iterator-yield.md - name: CS1639 href: ../misc/cs1639.md - - name: CS1640 - href: ./compiler-messages/cs1640.md - name: CS1644 href: ./compiler-messages/cs1644.md - name: CS1646 @@ -1646,8 +1619,6 @@ items: href: ./compiler-messages/cs8355.md - name: CS8422 href: ./compiler-messages/cs8422.md - - name: CS9036 - href: ./compiler-messages/property-declaration-errors.md - name: CS9043 href: ./compiler-messages/cs9043.md - name: Level 1 warning messages @@ -1796,12 +1767,6 @@ items: href: ../misc/cs0252.md - name: CS0253 href: ../misc/cs0253.md - - name: CS0278 - href: ../misc/cs0278.md - - name: CS0279 - href: ../misc/cs0279.md - - name: CS0280 - href: ../misc/cs0280.md - name: CS0444 href: ../misc/cs0444.md - name: CS0458 diff --git a/docs/csharp/language-reference/xmldoc/examples.md b/docs/csharp/language-reference/xmldoc/examples.md index a95f4fb6f0655..933ed211d55b1 100644 --- a/docs/csharp/language-reference/xmldoc/examples.md +++ b/docs/csharp/language-reference/xmldoc/examples.md @@ -44,6 +44,13 @@ Add XML comments for ``, ``, and, if necessary, `` to The C# compiler copies the XML nodes from the `extension` block to all members declared in that block. +For an extension indexer, `cref` syntax can reference the indexer and its accessors through the `extension` block that declares it, and it can reference the implementation methods on the containing class. The following examples show how to reference the `this[int]` indexer and its generated `get_Item` accessor from the preceding example: + +```csharp +/// +/// +``` + ## Math class example The following code shows a realistic example of adding doc comments to a math library. diff --git a/docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs b/docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs index cf8ec17faffd7..a852a1b31e471 100644 --- a/docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs +++ b/docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs @@ -362,6 +362,13 @@ public static IEnumerable Generate(int count, Func generat yield return generator(); } } + + /// + /// Gets the element at the specified position in the sequence. + /// + /// The zero-based position of the element to retrieve. + /// The element at the specified position. + public TSequence this[int index] => sequence.ElementAt(index); } } // diff --git a/docs/csharp/language-reference/xmldoc/snippets/xmldoc/xmldoc.csproj b/docs/csharp/language-reference/xmldoc/snippets/xmldoc/xmldoc.csproj index 556d004c40ed7..40c7c345f8c80 100644 --- a/docs/csharp/language-reference/xmldoc/snippets/xmldoc/xmldoc.csproj +++ b/docs/csharp/language-reference/xmldoc/snippets/xmldoc/xmldoc.csproj @@ -3,6 +3,7 @@ Exe net10.0 + preview enable enable xmldoc.xml diff --git a/docs/csharp/misc/cs0202.md b/docs/csharp/misc/cs0202.md deleted file mode 100644 index 4ba035827d1e6..0000000000000 --- a/docs/csharp/misc/cs0202.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -description: "Compiler Error CS0202" -title: "Compiler Error CS0202" -ms.date: 07/20/2015 -f1_keywords: - - "CS0202" -helpviewer_keywords: - - "CS0202" -ms.assetid: 7088850f-c206-4b95-9586-a0fa3d876c0c ---- -# Compiler Error CS0202 - -foreach requires that the return type 'type' of 'type.GetEnumerator()' must have a suitable public MoveNext method and public Current property - - A function, used to enable the use of foreach statements, cannot return a pointer or array; it must return an instance of a class that is able to act as an enumerator. The proper requirements to serve as an enumerator include a public Current property and a public MoveNext method. - -> [!NOTE] -> In C# 2.0, the compiler will automatically generate Current and MoveNext for you. For more information, see the code example in [Generic Interfaces](../programming-guide/generics/generic-interfaces.md). - - The following sample generates CS0202: - -```csharp -// CS0202.cs - -public class C1 -{ - public int Current - { - get - { - return 0; - } - } - - public bool MoveNext () - { - return false; - } - - public static implicit operator C1 (int c1) - { - return 0; - } -} - -public class C2 -{ - public int Current - { - get - { - return 0; - } - } - - public bool MoveNext () - { - return false; - } - - public C1[] GetEnumerator () - // try the following line instead - // public C1 GetEnumerator () - { - return null; - } -} - -public class MainClass -{ - public static void Main () - { - C2 c2 = new C2(); - - foreach (C1 x in c2) // CS0202 - { - System.Console.WriteLine(x.Current); - } - } -} -``` diff --git a/docs/csharp/misc/cs0230.md b/docs/csharp/misc/cs0230.md deleted file mode 100644 index 91f3a82660a7e..0000000000000 --- a/docs/csharp/misc/cs0230.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -description: "Compiler Error CS0230" -title: "Compiler Error CS0230" -ms.date: 07/20/2015 -f1_keywords: - - "CS0230" -helpviewer_keywords: - - "CS0230" -ms.assetid: 132e4623-d393-4a5f-a3f8-838a1bfbd1b3 ---- -# Compiler Error CS0230 - -Type and identifier are both required in a foreach statement - - A [foreach](../language-reference/statements/iteration-statements.md#the-foreach-statement) statement was poorly formed. - - The following sample generates CS0230: - -```csharp -// CS0230.cs -class MyClass -{ - public static void Main() - { - int[] myarray = new int[3] {1,2,3}; - - foreach (int in myarray) // CS0230 - { - Console.WriteLine(x); - } - } -} -``` - -and the sample below presents the same code, but with no CS0230 error: - -```csharp -class MyClass -{ - public static void Main() - { - int[] myarray = new int[3] {1,2,3}; - - foreach (int x in myarray) // Both type (int) and indentifier (x) are specified - { - Console.WriteLine(x); - } - } -} -``` diff --git a/docs/csharp/misc/cs0278.md b/docs/csharp/misc/cs0278.md deleted file mode 100644 index 29c4433b33b33..0000000000000 --- a/docs/csharp/misc/cs0278.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0278" -title: "Compiler Warning (level 2) CS0278" -ms.date: 07/20/2015 -f1_keywords: - - "CS0278" -helpviewer_keywords: - - "CS0278" -ms.assetid: 5418cbbe-bcec-4379-a6f6-410987beb96a ---- -# Compiler Warning (level 2) CS0278 - -'type' does not implement the 'pattern name' pattern. 'method name' is ambiguous with 'method name'. - -There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, the [`foreach` statement](../language-reference/statements/iteration-statements.md#the-foreach-statement) relies on the collection class implementing the "enumerable" pattern. - -CS0278 can occur if the compiler is unable to make the match due to ambiguities. For example, the "enumerable" pattern requires that there be a method called `MoveNext`, and your code might contain two methods called `MoveNext`. The compiler will attempt to find an interface to use, but it is recommended that you determine and resolve the cause of the ambiguity. - -## Example - - The following sample generates CS0278. - -```csharp -// CS0278.cs -using System.Collections.Generic; -public class myTest -{ - public static void TestForeach(W w) - where W: IEnumerable, IEnumerable - { - foreach (int i in w) {} // CS0278 - } -} -``` diff --git a/docs/csharp/misc/cs0279.md b/docs/csharp/misc/cs0279.md deleted file mode 100644 index 1219abfbd4d64..0000000000000 --- a/docs/csharp/misc/cs0279.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0279" -title: "Compiler Warning (level 2) CS0279" -ms.date: 07/20/2015 -f1_keywords: - - "CS0279" -helpviewer_keywords: - - "CS0279" -ms.assetid: 5e5faa8f-3d5b-4999-aa62-ff7f131a3e04 ---- -# Compiler Warning (level 2) CS0279 - -'type name' does not implement the 'pattern name' pattern. 'method name' is either static or not public. - - There are several statements in C# that rely on defined patterns, such as `foreach` and `using`. For example, `foreach` relies on the collection class implementing the enumerable pattern. This error occurs when the compiler is unable to make the match due to a method being declared `static` or not `public`. Methods in patterns are required to be instances of classes, and to be public. - -## Example - - The following example generates CS0279: - -```csharp -// CS0279.cs - -using System; -using System.Collections; - -public class myTest : IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield return 0; - } - - internal IEnumerator GetEnumerator() - { - yield return 0; - } - - public static void Main() - { - foreach (int i in new myTest()) {} // CS0279 - } -} -``` diff --git a/docs/csharp/misc/cs0280.md b/docs/csharp/misc/cs0280.md deleted file mode 100644 index 3b2cf791395b1..0000000000000 --- a/docs/csharp/misc/cs0280.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -description: "Compiler Warning (level 2) CS0280" -title: "Compiler Warning (level 2) CS0280" -ms.date: 07/20/2015 -f1_keywords: - - "CS0280" -helpviewer_keywords: - - "CS0280" -ms.assetid: 9b453478-92aa-4fd2-9b87-780fd138603a ---- -# Compiler Warning (level 2) CS0280 - -'type' does not implement the 'pattern name' pattern. 'method name' has the wrong signature. - - Two statements in C#, **foreach** and **using**, rely on predefined patterns, "collection" and "resource" respectively. This warning occurs when the compiler cannot match one of these statements to its pattern due to a method's incorrect signature. For example, the "collection" pattern requires that there be a method called which takes no parameters and returns a `boolean`. Your code might contain a method that has a parameter or perhaps returns an object. - - The "resource" pattern and `using` provide another example. The "resource" pattern requires the method; if you define a property with the same name, you will get this warning. - - To resolve this warning, ensure that the method signatures in your type match the signatures of the corresponding methods in the pattern, and ensure that you have no properties with the same name as a method required by the pattern. - -## Example - - The following sample generates CS0280. - -```csharp -// CS0280.cs -using System; -using System.Collections; - -public class ValidBase: IEnumerable -{ - IEnumerator IEnumerable.GetEnumerator() - { - yield return 0; - } - - internal IEnumerator GetEnumerator() - { - yield return 0; - } -} - -class Derived : ValidBase -{ - // field, not method - new public int GetEnumerator; -} - -public class Test -{ - public static void Main() - { - foreach (int i in new Derived()) {} // CS0280 - } -} -``` diff --git a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md index 9c6218dedcd3b..4ea353a2ab2cd 100644 --- a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md +++ b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md @@ -178,7 +178,6 @@ f1_keywords: - "CS8183" - "CS8184" - "CS8185" - - "CS8186" - "CS8187" - "CS8188" - "CS8189" @@ -225,21 +224,10 @@ f1_keywords: - "CS8383" - "CS8384" # C# 8.0 diagnostics - ## Async enumerables - - "CS8412" - - "CS8413" - - "CS8414" - - "CS8415" - - "CS8419" - - "CS8420" ## Static local functions - "CS8421" ## Attributes - "CS8423" - ## More async enumerators - - "CS8424" - - "CS8425" - - "CS8426" ## Index and range - "CS8428" - "CS8429" @@ -262,7 +250,6 @@ f1_keywords: - "CS9349" - "CS9350" - "CS9351" - - "CS9353" # Collection arguments: - "CS9354" - "CS9355" diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 92b994442b625..4c2d53605975b 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -113,6 +113,12 @@ items: items: - name: Use string interpolation href: fundamentals/tutorials/string-interpolation.md + - name: Expressions and statements + items: + - name: Selection statements + href: fundamentals/statements/selection.md + - name: Iteration statements + href: fundamentals/statements/iteration.md - name: Object-oriented programming items: - name: Classes, structs, and records diff --git a/docs/csharp/whats-new/csharp-15.md b/docs/csharp/whats-new/csharp-15.md index 176a6f0842cf6..7375d7b119f11 100644 --- a/docs/csharp/whats-new/csharp-15.md +++ b/docs/csharp/whats-new/csharp-15.md @@ -1,7 +1,7 @@ --- title: What's new in C# 15 description: Get an overview of the new features in C# 15. C# 15 ships with .NET 11. -ms.date: 06/16/2026 +ms.date: 07/08/2026 ms.topic: whats-new ms.update-cycle: 365-days ai-usage: ai-assisted @@ -13,6 +13,7 @@ C# 15 includes the following new features. Try these features by using the lates - [Collection expression arguments](#collection-expression-arguments) - [Union types](#union-types) - [Closed hierarchies](#closed-hierarchies) +- [Extension indexers](#extension-indexers) - [Memory safety](#memory-safety) C# 15 is the latest C# preview release. .NET 11 preview versions support C# 15. For more information, see [C# language versioning](../language-reference/configure-language-version.md). @@ -108,6 +109,31 @@ The `closed` modifier is a contextual keyword. A `closed` class is implicitly `a For more information, see the [closed modifier](../language-reference/keywords/closed.md) and [Closed hierarchy patterns](../language-reference/operators/patterns.md#closed-hierarchy-patterns) in the language reference, or the [feature specification](~/_csharplang/proposals/closed-hierarchies.md). You can copy the examples in this section, including the `ClosedAttribute` workaround, from the [keywords snippets project](https://github.com/dotnet/docs/blob/main/docs/csharp/language-reference/keywords/snippets/shared) in the `dotnet/docs` GitHub repository. +## Extension indexers + +Starting with C# 15, you can declare *indexers* in an `extension` block. Extension indexers let you index into a receiver as though the indexer were declared on the receiver type. Because indexers are always instance members, an extension block that declares an indexer must provide a named receiver parameter. + +The following example declares a get-only indexer on `IEnumerable` that returns the element at a specified position: + +```csharp +public static class SequenceIndexer +{ + extension(IEnumerable sequence) + { + public int this[int index] => sequence.ElementAt(index); + } +} +``` + +You index into the receiver as though the indexer were a member of the receiver type: + +```csharp +IEnumerable numbers = Enumerable.Range(1, 10); +int third = numbers[2]; +``` + +For more information, see [Extension declaration](../language-reference/keywords/extension.md#extension-indexers) in the language reference or the [feature specification](~/_csharplang/proposals/extension-indexers.md). + ## Memory safety C# 15 begins a multirelease effort to redefine memory safety in the language. The goal is to tie the `unsafe` context to the operations that actually access unmanaged memory, rather than to the existence of pointer types. Most memory safety vulnerabilities come from these access operations, so the language makes them stand out for reviewers and auditors. diff --git a/docs/csharp/whats-new/tutorials/extension-members.md b/docs/csharp/whats-new/tutorials/extension-members.md index 539ba6d78d29f..f312cdfcbe00f 100644 --- a/docs/csharp/whats-new/tutorials/extension-members.md +++ b/docs/csharp/whats-new/tutorials/extension-members.md @@ -1,45 +1,51 @@ --- -title: Explore extension members in C# 14 to enhance existing types -description: "C# 14 provides new syntax for extensions that support properties and operators, and enables extensions on a type as well as an instance. Learn to use them, and how to migrate existing extension methods to extension members" +title: Explore extension members in C# 14 and C# 15 to enhance existing types +description: "C# 14 extension members add properties and operators to existing types. C# 15 extension indexers add indexed access. Learn both with runnable Point and Path examples." author: billwagner ms.author: wiwagn ms.service: dotnet-csharp ms.topic: tutorial -ms.date: 10/06/2025 +ms.date: 07/15/2026 ai-usage: ai-assisted #customer intent: As a C# developer, I reduce repeated code by introducing extension members for common tasks --- -# Tutorial: Explore extension members in C# 14 +# Tutorial: Explore extension members in C# 14 and C# 15 -C# 14 introduces extension members, an enhancement to the existing extension methods. Extension members enable you to add properties and operators. You can also extend types in addition to instances of types. This capability allows you to create more natural and expressive APIs when extending types you don't control. +C# 14 introduced extension members, an enhancement to the existing extension methods. Extension members enable you to add properties and operators. You can also extend types as well as instances of types. C# 15 adds extension indexers, so an existing type can support indexed access from an extension block. -In this tutorial, you explore extension members by enhancing the `System.Drawing.Point` type with mathematical operations, coordinate transformations, and utility properties. You learn how to migrate existing extension methods to the new extension member syntax and understand when to use each approach. +In this tutorial, you explore extension members by enhancing the `System.Drawing.Point` type with mathematical operations, coordinate transformations, and utility properties. Then you add indexed access to a `Path` type that stores point-to-point offsets. You learn how to migrate existing extension methods to the new extension member syntax and when each approach fits. In this tutorial, you: > [!div class="checklist"] > -> * Create extension members with static properties and operators. +> * Create C# 14 extension members with static properties and operators. > * Implement coordinate transformations using extension members. > * Migrate traditional extension methods to extension member syntax. +> * Add a C# 15 extension indexer that reads and updates absolute points in a path. > * Compare extension members with traditional extension methods. ## Prerequisites -- The .NET 10 SDK. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet/10.0). -- Visual Studio 2026. Download it from the [Visual Studio page](https://visualstudio.microsoft.com). +- The .NET 11 preview SDK. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet/11.0). +- Visual Studio 2026 with preview features enabled. Download it from the [Visual Studio page](https://visualstudio.microsoft.com). +- This sample sets `preview` because extension indexers are a C# 15 preview feature. ## Create the sample application -Start by creating a console application that demonstrates both traditional extension methods and the new extension members syntax. You'll create extensions for the type. This type comes from the `System.Drawing` namespace and is typically used in Windows Forms applications. +Start by creating a console application that demonstrates both traditional extension methods and the new extension members syntax. You create extensions for the type. This type comes from the `System.Drawing` namespace and is typically used in Windows Forms applications. -1. Create a new console application: +1. Create a new console application. ```dotnetcli dotnet new console -n PointExtensions cd PointExtensions ``` +1. Update the project file so the sample targets .NET 11 and uses preview language features: + + :::code language="xml" source="snippets/PointExtensions/PointExtensions.csproj"::: + 1. Copy the following code into a new file named `ExtensionMethods.cs`: :::code language="csharp" source="snippets/PointExtensions/ExtensionMethods.cs"::: @@ -95,11 +101,11 @@ Next, examine the following code that performs arithmetic with points: :::code language="csharp" source="snippets/PointExtensions/IncludedElements.cs" id="PointArithmetic"::: -Traditional extension methods can't add operators to existing types. You must implement arithmetic operations manually, making the code verbose and harder to read. The algorithm gets duplicated whenever the operation is needed, which creates more opportunities for small mistakes to enter the code base. It's better to place that code in one location. Add the following operators to your extension block in `NewExtensionsMembers.cs`: +Traditional extension methods can't add operators to existing types. You must implement arithmetic operations manually, which makes the code verbose and harder to read. The algorithm gets duplicated whenever you need the operation, which creates more opportunities for small mistakes to enter the code base. It's better to place that code in one location. Add the following operators to your extension block in `NewExtensionsMembers.cs`: :::code language="csharp" source="snippets/PointExtensions/NewExtensionsMembers.cs" id="ArithmeticOperators"::: -Extension members enable you to add operators directly to existing types. Now you can perform arithmetic operations using natural syntax: +By using extension members, you can add operators directly to existing types. Now you can perform arithmetic operations by using natural syntax: :::code language="csharp" source="snippets/PointExtensions/ExtensionMemberDemonstrations.cs" id="PointArithmeticWithOperators"::: @@ -135,27 +141,49 @@ Extension members use a different syntax but provide the same functionality. Add :::code language="csharp" source="snippets/PointExtensions/NewExtensionsMembers.cs" id="TransformationMethods"::: -The preceding code doesn't compile yet. It's the first extension you wrote that extends an *instance* of the `Point` class, instead of the type itself. To support instance extensions, your extension block needs to name the receiver parameter. Edit the following line: +These methods extend an instance of the `Point` struct, not the `Point` type. The extension block names the receiver parameter so the method body can read that point. The sample uses `extension(ref Point point)` because `Translate`, `Scale`, and `Rotate` change the caller's `Point`. Without `ref`, those methods would update a copy of the struct, and the caller wouldn't see the change. -```csharp - extension (Point) -``` +You can call these new instance methods exactly as you accessed traditional extension methods: + +:::code language="csharp" source="snippets/PointExtensions/ExtensionMemberDemonstrations.cs" id="InstanceMethods"::: -So that it gives a name to the `Point` instance: +The key difference is syntax: extension members use `extension (Type variableName)` instead of `this Type variableName`. -```csharp - extension (Point point) -``` +## Add extension indexers -Now, the code compiles. You can call these new instance methods exactly as you accessed traditional extension methods: +C# 15 adds indexers to `extension` blocks. An indexer has no name. Code accesses it with `this[...]` in the declaration and with indexed syntax at the call site. -:::code language="csharp" source="snippets/PointExtensions/ExtensionMemberDemonstrations.cs" id="InstanceMethods"::: +Imagine a path type that stores each step as a relative offset. When you ask for `path[i]`, you want the absolute point at that step. When you assign `path[i] = target`, you want the type to update the one offset that gets you there. Indexed access reads like "the point at this step" and keeps the offset-to-point math in one place. -The key difference is syntax: extension members use `extension (Type variableName)` instead of `this Type variableName`. +Imagine that `Path` came from a library. If you don't own the type, you can't add an indexer to its source. Before C# 15, you could add methods, but you couldn't add `this[...]` indexed access to a type you don't control. This tutorial defines `Path` so the sample is runnable; think of it as standing in for that library type. + +For this section, add a `Path` type. The type stores a sequence of `(dX, dY)` offsets. Each offset says how far to move from the previous point. The first offset starts at `Point.Origin`, the static extension property you added earlier. + +Create a new file named `Path.cs` in the same project as the other sample files. Add the `Path` type to the `ExtensionMembers` namespace in that file. Keeping `Path` in this namespace makes it your sample type, not . The demo file uses a `using Path = ExtensionMembers.Path;` alias, so every `Path` in the demo means the sample path type. + +:::code language="csharp" source="snippets/PointExtensions/Path.cs" id="PathType"::: + +Now add an indexer for `Path`. Put this code in the existing `PointExtensions` static class in `NewExtensionsMembers.cs`. Add it as a new `extension(Path path)` block, separate from the `extension(Point)` block for static members and operators and separate from the `extension(ref Point point)` block for instance methods: + +:::code language="csharp" source="snippets/PointExtensions/NewExtensionsMembers.cs" id="PathIndexer"::: + +Indexers are always instance members, so this new extension block must name the receiver: `extension(Path path)`. A block written as `extension(Path)` wouldn't provide a `path` variable for the indexer body. + +`Path` is a class that owns a list of offsets. The indexer doesn't need a `ref` receiver because the setter changes the contents of that existing `Path` object. + +The getter starts at `Point.Origin`, then adds the offsets from index `0` through the requested index. With offsets `(2, 3)`, `(1, 1)`, and `(-1, 4)`, the absolute points are `(2, 3)`, `(3, 4)`, and `(2, 8)`. + +The setter receives a target absolute point. It leaves earlier offsets alone and changes only the offset at the requested index. The new offset is the target point minus the absolute point at the previous index. Later points shift because they remain relative to the changed offset. + +Now, use the indexer to read and write points along the path: + +:::code language="csharp" source="snippets/PointExtensions/ExtensionMemberDemonstrations.cs" id="PathIndexerUse"::: + +Both accessors share a small private `ValidatePathIndex` helper in the same `PointExtensions` class that bounds-checks the index and throws when it doesn't refer to an offset in the path. ## Completed sample -The final example shows the advantages when you combine static properties, operators, and instance methods to create comprehensive type extensions. +The final example shows the advantages when you combine static properties, operators, instance methods, and an indexer to create comprehensive type extensions. Compare the extension member version: @@ -171,15 +199,17 @@ This example demonstrates how extension members create a cohesive API that feels - Apply mathematical operators naturally (`point + offset`, `point * scale`) - Chain transformations using both operators and methods - Convert between related types (`ToVector()`) +- Read and update absolute points along a path with `path[index]` ### Migration benefits -When migrating from traditional extension methods to extension members, you gain: +When you migrate from traditional extension methods to extension members, you get: 1. **Static properties**: Add constants and computed values to types. 1. **Operators**: Enable natural mathematical and logical operations. +1. **Indexers**: Add C# 15 indexed access that can compute values from an existing type and update its stored state. 1. **Unified syntax**: All extension logic uses the same `extension` declaration. -1. **Type-level extensions**: Extend the type itself, not just instances. +1. **Type-level extensions**: Extend the type itself, not only instances. Run the complete application to see both approaches side by side and observe how extension members provide a more integrated development experience. @@ -187,4 +217,7 @@ Run the complete application to see both approaches side by side and observe how - [Extension methods (C# Programming Guide)](../../programming-guide/classes-and-structs/extension-methods.md) - [What's new in C# 14](../csharp-14.md) +- [What's new in C# 15](../csharp-15.md) +- [`extension` keyword (C# reference)](../../language-reference/keywords/extension.md) +- [Extension indexers feature specification](~/_csharplang/proposals/extension-indexers.md) - [Operator overloading (C# reference)](../../language-reference/operators/operator-overloading.md) diff --git a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/ExtensionMemberDemonstrations.cs b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/ExtensionMemberDemonstrations.cs index 6f7fb74cbd0d7..5e1ca44f14ac9 100644 --- a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/ExtensionMemberDemonstrations.cs +++ b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/ExtensionMemberDemonstrations.cs @@ -1,6 +1,7 @@ using System.Drawing; using System.Numerics; using ExtensionMembers; +using Path = ExtensionMembers.Path; public static class ExtensionMemberDemonstrations { @@ -13,6 +14,7 @@ public static void NewExtensionMembers() ArithmeticWithPoints(); DiscreteArithmeticWithPoints(); ExtensionMethods(); + PathIndexer(); MoreExamples(); } @@ -117,10 +119,29 @@ static void ExtensionMethods() // } + static void PathIndexer() + { + // + Console.WriteLine("5. Path Indexer"); + Console.WriteLine("---------------"); + + Path path = new([(dX: 2, dY: 3), (dX: 1, dY: 1), (dX: -1, dY: 4)]); + Console.WriteLine($"First point: {path[0]}"); + Console.WriteLine($"Second point: {path[1]}"); + Console.WriteLine($"Third point: {path[2]}"); + + path[1] = new Point(10, 10); + Console.WriteLine("After setting the second point to {X=10,Y=10}:"); + Console.WriteLine($"Second point: {path[1]}"); + Console.WriteLine($"Third point: {path[2]}"); + Console.WriteLine(); + // + } + static void MoreExamples() { // - Console.WriteLine("5. Complex Scenarios"); + Console.WriteLine("6. Complex Scenarios"); Console.WriteLine("-------------------"); // Combining operators and methods diff --git a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/NewExtensionsMembers.cs b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/NewExtensionsMembers.cs index de80d85881d67..26c2964911269 100644 --- a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/NewExtensionsMembers.cs +++ b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/NewExtensionsMembers.cs @@ -5,7 +5,7 @@ namespace ExtensionMembers; public static class PointExtensions { - extension(ref Point point) + extension(Point) { public static Point Origin => Point.Empty; @@ -27,7 +27,10 @@ public static class PointExtensions public static Point operator -(Point left, (int dx, int dy) scale) => new Point(left.X - scale.dx, left.Y - scale.dy); // + } + extension(ref Point point) + { // public Vector2 ToVector() => new Vector2(point.X, point.Y); @@ -55,6 +58,49 @@ public void Rotate(int angleInDegrees) point.Y = (int)newY; } // + } + + // + extension(Path path) + { + public Point this[int index] + { + get + { + ValidatePathIndex(path, index); + + Point absolutePoint = Point.Origin; + for (int current = 0; current <= index; current++) + { + var offset = path.GetOffset(current); + absolutePoint += offset; + } + return absolutePoint; + } + set + { + ValidatePathIndex(path, index); + + Point previousPoint = Point.Origin; + for (int current = 0; current < index; current++) + { + var offset = path.GetOffset(current); + previousPoint += offset; + } + + path.SetOffset(index, (value.X - previousPoint.X, value.Y - previousPoint.Y)); + } + } + } + + private static void ValidatePathIndex(Path path, int index) + { + if (index < 0 || index >= path.Count) + { + throw new ArgumentOutOfRangeException(nameof(index), index, + "Index must refer to an offset in the path."); + } } + // } diff --git a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/Path.cs b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/Path.cs new file mode 100644 index 0000000000000..b4a32ff935140 --- /dev/null +++ b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/Path.cs @@ -0,0 +1,20 @@ +namespace ExtensionMembers; + +// +public sealed class Path +{ + private readonly List<(int dX, int dY)> offsets = []; + + public Path(IEnumerable<(int dX, int dY)> offsets) + { + this.offsets.AddRange(offsets); + } + + public int Count => offsets.Count; + + internal (int dX, int dY) GetOffset(int index) => offsets[index]; + + internal void SetOffset(int index, (int dX, int dY) offset) => + offsets[index] = offset; +} +// diff --git a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/PointExtensions.csproj b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/PointExtensions.csproj index ed9781c223ab9..1de1aa47a7270 100644 --- a/docs/csharp/whats-new/tutorials/snippets/PointExtensions/PointExtensions.csproj +++ b/docs/csharp/whats-new/tutorials/snippets/PointExtensions/PointExtensions.csproj @@ -2,7 +2,8 @@ Exe - net10.0 + net11.0 + preview enable enable diff --git a/docs/navigate/migration-guide/toc.yml b/docs/navigate/migration-guide/toc.yml index 83bf685a6fbde..ff97484f8d9e4 100644 --- a/docs/navigate/migration-guide/toc.yml +++ b/docs/navigate/migration-guide/toc.yml @@ -129,15 +129,5 @@ items: - name: How to analyze a project href: ../../core/porting/upgrade-assistant-how-to-analyze.md displayName: upgrade assistant - - name: Project upgrade guide - items: - - name: ASP.NET - href: /aspnet/core/migration/fx-to-core/tooling - - name: Windows Presentation Foundation - href: /dotnet/desktop/wpf/migration/ - - name: Windows Forms - href: /dotnet/desktop/winforms/migration/ - - name: Universal Windows Platform - href: /windows/apps/windows-app-sdk/migrate-to-windows-app-sdk/upgrade-assistant - name: Telemetry href: ../../core/porting/upgrade-assistant-telemetry.md diff --git a/samples/snippets/csharp/VS_Snippets_CLR/HowToDecryptXMLElementAsymmetric/cs/decryptxml.csproj b/samples/snippets/csharp/VS_Snippets_CLR/HowToDecryptXMLElementAsymmetric/cs/decryptxml.csproj index ba8fb029b6251..780cbcae40000 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/HowToDecryptXMLElementAsymmetric/cs/decryptxml.csproj +++ b/samples/snippets/csharp/VS_Snippets_CLR/HowToDecryptXMLElementAsymmetric/cs/decryptxml.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/ConstructionCS/ConstructionCS.csproj b/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/ConstructionCS/ConstructionCS.csproj index c5dbf580ddb60..9eea6bfe76a44 100644 --- a/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/ConstructionCS/ConstructionCS.csproj +++ b/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/ConstructionCS/ConstructionCS.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/TransformationCS/TransformationCS.csproj b/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/TransformationCS/TransformationCS.csproj index a5c1c01ef3d34..61753abe9c52d 100644 --- a/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/TransformationCS/TransformationCS.csproj +++ b/samples/snippets/csharp/roslyn-sdk/SyntaxTransformationQuickStart/TransformationCS/TransformationCS.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/snippets/fsharp/tour.fs b/samples/snippets/fsharp/tour.fs index 24e8a458d2371..72db5a0aa5851 100644 --- a/samples/snippets/fsharp/tour.fs +++ b/samples/snippets/fsharp/tour.fs @@ -936,7 +936,7 @@ module ImplementingInterfaces = /// This is an object that implements IDisposable via an Object Expression - /// Unlike other languages such as C# or Java, a new type definition is not needed + /// Unlike other languages, such as C#, a new type definition is not needed /// to implement an interface. let interfaceImplementation = { new System.IDisposable with diff --git a/samples/snippets/visualbasic/VS_Snippets_CLR/HowToEncryptXMLElementX509/vb/encryptxml.vbproj b/samples/snippets/visualbasic/VS_Snippets_CLR/HowToEncryptXMLElementX509/vb/encryptxml.vbproj index 6bd19fdd677f6..fb11213c748b3 100644 --- a/samples/snippets/visualbasic/VS_Snippets_CLR/HowToEncryptXMLElementX509/vb/encryptxml.vbproj +++ b/samples/snippets/visualbasic/VS_Snippets_CLR/HowToEncryptXMLElementX509/vb/encryptxml.vbproj @@ -6,7 +6,7 @@ - +