diff --git a/.github/agents/breakingchange.agent.md b/.github/agents/breakingchange.agent.md index dd1374a494896..27e3712c3fd43 100644 --- a/.github/agents/breakingchange.agent.md +++ b/.github/agents/breakingchange.agent.md @@ -16,20 +16,22 @@ Start with this header (replace placeholders): ``` --- -title: "Breaking change - " +title: "Breaking change: " description: "Learn about the breaking change in where ." ms.date: ai-usage: ai-assisted --- ``` -> **Note:** Use today's date in the format MM/DD/YYYY. This date cannot be earlier than 11/12/2025. +> **Note:** +> - Use today's date in the format MM/DD/YYYY. This date cannot be earlier than 01/12/2026. +> - Do NOT include ms.custom metadata with an issue number. Then, include these sections in this order: ### 1. H1 Title -- Use the header title, but remove "Breaking change - ". +- Use the header title, but remove "Breaking change: ". **Intro paragraph:** Summarize the breaking change. diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index ead0c347b3639..d45656b0b4c0f 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -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@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v3.29.5 + uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3.29.5 with: sarif_file: results.sarif diff --git a/.github/workflows/snippets5000.yml b/.github/workflows/snippets5000.yml index 1a900361ad631..ecc882920fb30 100644 --- a/.github/workflows/snippets5000.yml +++ b/.github/workflows/snippets5000.yml @@ -41,7 +41,7 @@ jobs: # Get the latest preview SDK (or sdk not installed by the runner) - name: Setup .NET if: ${{ env.DOTNET_DO_INSTALL == 'true' }} - uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 #@5.0.1 + uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 #@5.1.0 with: dotnet-version: ${{ env.DOTNET_VERSION }} dotnet-quality: ${{ env.DOTNET_QUALITY }} diff --git a/.openpublishing.redirection.fundamentals.json b/.openpublishing.redirection.fundamentals.json index 913887e237ead..88ca14da3ce61 100644 --- a/.openpublishing.redirection.fundamentals.json +++ b/.openpublishing.redirection.fundamentals.json @@ -237,6 +237,10 @@ "source_path_from_root": "/docs/fundamentals/productivity/configure-code-analysis-rules.md", "redirect_url": "/dotnet/fundamentals/code-analysis/configuration-options" }, + { + "source_path_from_root": "/docs/fundamentals/reflection/reflection.md", + "redirect_url": "/dotnet/fundamentals/reflection/overview" + }, { "source_path_from_root": "/docs/fundamentals/runtime-libraries/system-data-linq-dataloadoptions.md", "redirect_url": "/dotnet/framework/data/adonet/sql/linq/" diff --git a/docfx.json b/docfx.json index 5787be90f43ba..32baf4eabedc3 100644 --- a/docfx.json +++ b/docfx.json @@ -191,48 +191,46 @@ "_csharpstandard/standard/*.md": "status: needs triaging" }, "social_image_url": { - "docs/aspire/**/*.*": "/dotnet/media/dotnet-aspire-logo.png", + "docs/architecture/**/*.*": "/dotnet/media/dotnet-bot_microservices.png", "docs/azure/**/*.*": "/dotnet/media/dotnet-bot_cloud-apps.png", - "docs/orleans/**/*.*": "/dotnet/media/dotnet-orleans.png", + "docs/csharp/**/*.*": "/dotnet/media/logo_csharp.png", + "docs/fsharp/**/*.*": "/dotnet/media/logo_fsharp.png", "docs/iot/**/*.*": "/dotnet/media/dotnet-bot_iot.png", - "docs/maui/**/*.*": "/dotnet/media/dotnet-bot_mobile-apps-xamarin.png", "docs/machine-learning/**/*.*": "/dotnet/media/dotnet-bot_machinelearning.png", - "docs/architecture/**/*.*": "/dotnet/media/dotnet-bot_microservices.png", + "docs/orleans/**/*.*": "/dotnet/media/dotnet-orleans.png", "docs/standard/**/*.*": "/dotnet/media/dot-net-cross-platform.png", - "docs/csharp/**/*.*": "/dotnet/media/logo_csharp.png", - "docs/fsharp/**/*.*": "/dotnet/media/logo_fsharp.png", "docs/visual-basic/**/*.*": "/dotnet/media/logo_vb.png" }, "feedback_product_url": { "docs/azure/sdk/**/*.*": "https://github.com/azure/azure-sdk-for-net", "docs/core/porting/upgrade-assistant*.md": "https://github.com/dotnet/upgrade-assistant/issues/new/choose", "docs/fsharp/**/**.md": "https://github.com/dotnet/fsharp", - "docs/orleans/**/**.md": "https://github.com/dotnet/orleans", "docs/fundamentals/code-analysis/quality-rules/**/*.md": "https://github.com/dotnet/roslyn-analyzers/issues", "docs/fundamentals/code-analysis/quality-rules/**/il*.md": "https://github.com/mono/linker/issues", "docs/fundamentals/code-analysis/style-rules/**/*.md": "https://github.com/dotnet/roslyn/issues", "docs/machine-learning/**/**.md": "https://github.com/dotnet/machinelearning", + "docs/orleans/**/**.md": "https://github.com/dotnet/orleans", "docs/standard/data/sqlite/**/*.md": "https://github.com/dotnet/efcore" }, "ms.service": { - "_csharplang/**/*.md": "dotnet-csharp", - "_csharpstandard/**/*.md": "dotnet-csharp", - "_roslyn/docs/compilers/CSharp/*.md": "dotnet-csharp", - "_vblang/spec/*.md": "dotnet-visualbasic", - "docs/architecture/**/**.md": "dotnet-architecture", - "docs/azure/**/*.*": "dotnet-azure", - "docs/core/**/*.*": "dotnet-fundamentals", - "docs/csharp/**/*.*": "dotnet-csharp", - "docs/framework/**/**.md": "dotnet-framework", - "docs/fsharp/**/**.md": "dotnet-fsharp", - "docs/fundamentals/**/*.md": "dotnet-fundamentals", - "docs/machine-learning/**/*.*": "dotnet-ml", - "docs/standard/**/**.md": "dotnet-fundamentals", - "docs/standard/data/**/**.md": "dotnet-data", - "docs/standard/design-guidelines/*.md": "dotnet", - "docs/standard/security/*.md": "dotnet", - "docs/visual-basic/**/**.md": "dotnet-visualbasic", - "docs/orleans/**/**.md": "dotnet-orleans" + "_csharplang/**/*.{md,yml}": "dotnet-csharp", + "_csharpstandard/**/*.{md,yml}": "dotnet-csharp", + "_roslyn/docs/compilers/CSharp/*.{md,yml}": "dotnet-csharp", + "_vblang/spec/*.{md,yml}": "dotnet-visualbasic", + "docs/architecture/**/**.{md,yml}": "dotnet-architecture", + "docs/azure/**/*.{md,yml}": "dotnet-azure", + "docs/core/**/*.{md,yml}": "dotnet-fundamentals", + "docs/csharp/**/*.{md,yml}": "dotnet-csharp", + "docs/framework/**/**.{md,yml}": "dotnet-framework", + "docs/fsharp/**/**.{md,yml}": "dotnet-fsharp", + "docs/fundamentals/**/*.{md,yml}": "dotnet-fundamentals", + "docs/machine-learning/**/*.{md,yml}": "dotnet-ml", + "docs/standard/**/**.{md,yml}": "dotnet-fundamentals", + "docs/standard/data/**/**.{md,yml}": "dotnet-data", + "docs/standard/design-guidelines/*.{md,yml}": "dotnet", + "docs/standard/security/*.{md,yml}": "dotnet", + "docs/visual-basic/**/**.{md,yml}": "dotnet-visualbasic", + "docs/orleans/**/**.{md,yml}": "dotnet-orleans" }, "ms.topic": { "_csharplang/**/*.md": "language-reference", @@ -328,186 +326,184 @@ "docs/visual-basic/**/**.md": "vb" }, "author": { - "_csharplang/**/*.md": "billwagner", - "_csharpstandard/**/*.md": "billwagner", - "_roslyn/docs/compilers/CSharp/*.md": "billwagner", - "_vblang/spec/*.md": "billwagner", - "docs/ai/**/*.*": "gewarren", - "docs/architecture/**/**.md": "jamesmontemagno", - "docs/architecture/grpc-for-wcf-developers/**/**.md": "JamesNK", - "docs/architecture/modernize-desktop/**/**.md": "OliaG", - "docs/azure/**/*.*": "alexwolfmsft", - "docs/core/**/**.md": "gewarren", - "docs/core/compatibility/**/**.md": "gewarren", - "docs/core/deploying/**/**.md": "adegeo", - "docs/core/diagnostics/**/**.md": "tommcdon", - "docs/core/extensions/**/**.md": "gewarren", - "docs/core/docker/**/**.md": "adegeo", - "docs/core/install/**/**.md": "adegeo", - "docs/core/native-interop/**/**.md": "jkoritzinsky", - "docs/core/porting/github-copilot-app-modernization/**/*.*": "adegeo", - "docs/core/project-sdk/**/**.md": "gewarren", - "docs/core/resilience/**/**.md": "gewarren", - "docs/core/runtime-config/**/**.md": "gewarren", - "docs/core/testing/**/**.md": "meaghanlewis", - "docs/core/tools/**/**.md": "meaghanlewis", - "docs/core/tutorials/**/**.md": "meaghanlewis", - "docs/core/versions/**/**.md": "billwagner", - "docs/core/whats-new/**/**.md": "billwagner", - "docs/csharp/**/*.*": "billwagner", - "docs/framework/**/**.md": "gewarren", - "docs/framework/additional-apis/pos-for-net/**/**.md": "TerryWarwick", - "docs/framework/app-domains/**/**.md": "gewarren", - "docs/framework/configure-apps/file-schema/network/**/**.md": "karelz", - "docs/framework/configure-apps/file-schema/wcf/**/**.md": "mconnew", - "docs/framework/configure-apps/file-schema/winforms/**/**.md": "adegeo", - "docs/framework/data/**/**.md": "cmastr", - "docs/framework/deployment/**/**.md": "adegeo", - "docs/framework/get-started/**/**.md": "gewarren", - "docs/framework/install/**/**.md": "adegeo", - "docs/framework/migration-guide/**/**.md": "gewarren", - "docs/framework/misc/**/**.md": "gewarren", - "docs/framework/network-programming/**/**.md": "karelz", - "docs/framework/performance/**/**.md": "billwagner", - "docs/framework/reflection-and-codedom/**/**.md": "adegeo", - "docs/framework/resources/**/**.md": "adegeo", - "docs/framework/tools/**/**.md": "gewarren", - "docs/framework/ui-automation/**/**.md": "adegeo", - "docs/framework/unmanaged-api/alink/**/**.md": "jeffschwMSFT", - "docs/framework/unmanaged-api/debugging/**/**.md": "tommcdon", - "docs/framework/unmanaged-api/diagnostics/**/**.md": "tommcdon", - "docs/framework/unmanaged-api/fusion/**/**.md": "jeffschwMSFT", - "docs/framework/unmanaged-api/hosting/**/**.md": "jeffschwMSFT", - "docs/framework/unmanaged-api/profiling/**/**.md": "tommcdon", - "docs/framework/unmanaged-api/strong-naming/**/**.md": "jeffschwMSFT", - "docs/framework/unmanaged-api/tlbexp/**/**.md": "jeffschwMSFT", - "docs/framework/whats-new/**/**.md": "gewarren", - "docs/framework/wcf/**/**.md": "mconnew", - "docs/fsharp/**/**.md": "billwagner", - "docs/fundamentals/code-analysis/**/**.md": "gewarren", - "docs/fundamentals/networking/**/**.md": "gewarren", - "docs/fundamentals/runtime-libraries/**/**.md": "gewarren", - "docs/fundamentals/syslib-diagnostics/**/**.md": "gewarren", - "docs/machine-learning/**/**.md": "gewarren", - "docs/orleans/**/*.*": "meaghanlewis", - "docs/standard/**/**.md": "gewarren", - "docs/standard/analyzers/**/**.md": "gewarren", - "docs/standard/assembly/**/**.md": "gewarren", - "docs/standard/asynchronous-programming-patterns/**/**.md": "billwagner", - "docs/standard/attributes/**/**.md": "gewarren", - "docs/standard/base-types/**/**.md": "adegeo", - "docs/standard/collections/**/**.md": "adegeo", - "docs/standard/commandline/**/**.md": "gewarren", - "docs/standard/data/**/**.md": "gewarren", - "docs/standard/data/sqlite/**/**.md": "ajcvickers", - "docs/standard/datetime/**/**.md": "adegeo", - "docs/standard/design-guidelines/**/**.md": "KrzysztofCwalina", - "docs/standard/events/**/**.md": "adegeo", - "docs/standard/exceptions/**/**.md": "gewarren", - "docs/standard/garbage-collection/**/**.md": "gewarren", - "docs/standard/generics/**/**.md": "adegeo", - "docs/standard/globalization-localization/**/**.md": "adegeo", - "docs/standard/io/**/**.md": "adegeo", - "docs/standard/library-guidance/**/**.md": "jamesnk", - "docs/standard/linq/**/**.md": "billwagner", - "docs/standard/memory-and-spans/**/**.md": "gewarren", - "docs/standard/native-interop/**/**.md": "jkoritzinsky", - "docs/standard/parallel-programming/**/**.md": "adegeo", - "docs/standard/security/**/**.md": "billwagner", - "docs/standard/serialization/**/**.md": "gewarren", - "docs/standard/threading/**/**.md": "billwagner", - "docs/standard/whats-new/**/**.md": "gewarren", - "docs/visual-basic/**/**.md": "billwagner", - "docs/whats-new/**/**.md": "billwagner", + "_csharplang/**/*.{md,yml}": "billwagner", + "_csharpstandard/**/*.{md,yml}": "billwagner", + "_roslyn/docs/compilers/CSharp/*.{md,yml}": "billwagner", + "_vblang/spec/*.{md,yml}": "billwagner", + "docs/ai/**/*.{md,yml}": "gewarren", + "docs/architecture/**/**.{md,yml}": "jamesmontemagno", + "docs/architecture/grpc-for-wcf-developers/**/**.{md,yml}": "JamesNK", + "docs/azure/**/*.{md,yml}": "alexwolfmsft", + "docs/core/**/**.{md,yml}": "gewarren", + "docs/core/compatibility/**/**.{md,yml}": "gewarren", + "docs/core/deploying/**/**.{md,yml}": "adegeo", + "docs/core/diagnostics/**/**.{md,yml}": "tommcdon", + "docs/core/extensions/**/**.{md,yml}": "gewarren", + "docs/core/docker/**/**.{md,yml}": "adegeo", + "docs/core/install/**/**.{md,yml}": "adegeo", + "docs/core/native-interop/**/**.{md,yml}": "jkoritzinsky", + "docs/core/porting/github-copilot-app-modernization/**/*.{md,yml}": "adegeo", + "docs/core/project-sdk/**/**.{md,yml}": "gewarren", + "docs/core/resilience/**/**.{md,yml}": "gewarren", + "docs/core/runtime-config/**/**.{md,yml}": "gewarren", + "docs/core/testing/**/**.{md,yml}": "meaghanlewis", + "docs/core/tools/**/**.{md,yml}": "meaghanlewis", + "docs/core/tutorials/**/**.{md,yml}": "meaghanlewis", + "docs/core/versions/**/**.{md,yml}": "billwagner", + "docs/core/whats-new/**/**.{md,yml}": "billwagner", + "docs/csharp/**/*.{md,yml}": "billwagner", + "docs/framework/**/**.{md,yml}": "gewarren", + "docs/framework/additional-apis/pos-for-net/**/**.{md,yml}": "TerryWarwick", + "docs/framework/app-domains/**/**.{md,yml}": "gewarren", + "docs/framework/configure-apps/file-schema/network/**/**.{md,yml}": "karelz", + "docs/framework/configure-apps/file-schema/wcf/**/**.{md,yml}": "mconnew", + "docs/framework/configure-apps/file-schema/winforms/**/**.{md,yml}": "adegeo", + "docs/framework/data/**/**.{md,yml}": "cmastr", + "docs/framework/deployment/**/**.{md,yml}": "adegeo", + "docs/framework/get-started/**/**.{md,yml}": "gewarren", + "docs/framework/install/**/**.{md,yml}": "adegeo", + "docs/framework/migration-guide/**/**.{md,yml}": "gewarren", + "docs/framework/misc/**/**.{md,yml}": "gewarren", + "docs/framework/network-programming/**/**.{md,yml}": "karelz", + "docs/framework/performance/**/**.{md,yml}": "billwagner", + "docs/framework/reflection-and-codedom/**/**.{md,yml}": "adegeo", + "docs/framework/resources/**/**.{md,yml}": "adegeo", + "docs/framework/tools/**/**.{md,yml}": "gewarren", + "docs/framework/ui-automation/**/**.{md,yml}": "adegeo", + "docs/framework/unmanaged-api/alink/**/**.{md,yml}": "jeffschwMSFT", + "docs/framework/unmanaged-api/debugging/**/**.{md,yml}": "tommcdon", + "docs/framework/unmanaged-api/diagnostics/**/**.{md,yml}": "tommcdon", + "docs/framework/unmanaged-api/fusion/**/**.{md,yml}": "jeffschwMSFT", + "docs/framework/unmanaged-api/hosting/**/**.{md,yml}": "jeffschwMSFT", + "docs/framework/unmanaged-api/profiling/**/**.{md,yml}": "tommcdon", + "docs/framework/unmanaged-api/strong-naming/**/**.{md,yml}": "jeffschwMSFT", + "docs/framework/unmanaged-api/tlbexp/**/**.{md,yml}": "jeffschwMSFT", + "docs/framework/whats-new/**/**.{md,yml}": "gewarren", + "docs/framework/wcf/**/**.{md,yml}": "mconnew", + "docs/fsharp/**/**.{md,yml}": "billwagner", + "docs/fundamentals/code-analysis/**/**.{md,yml}": "gewarren", + "docs/fundamentals/networking/**/**.{md,yml}": "gewarren", + "docs/fundamentals/runtime-libraries/**/**.{md,yml}": "gewarren", + "docs/fundamentals/syslib-diagnostics/**/**.{md,yml}": "gewarren", + "docs/machine-learning/**/**.{md,yml}": "gewarren", + "docs/orleans/**/*.{md,yml}": "meaghanlewis", + "docs/standard/**/**.{md,yml}": "gewarren", + "docs/standard/analyzers/**/**.{md,yml}": "gewarren", + "docs/standard/assembly/**/**.{md,yml}": "gewarren", + "docs/standard/asynchronous-programming-patterns/**/**.{md,yml}": "billwagner", + "docs/standard/attributes/**/**.{md,yml}": "gewarren", + "docs/standard/base-types/**/**.{md,yml}": "adegeo", + "docs/standard/collections/**/**.{md,yml}": "adegeo", + "docs/standard/commandline/**/**.{md,yml}": "gewarren", + "docs/standard/data/**/**.{md,yml}": "gewarren", + "docs/standard/data/sqlite/**/**.{md,yml}": "ajcvickers", + "docs/standard/datetime/**/**.{md,yml}": "adegeo", + "docs/standard/design-guidelines/**/**.{md,yml}": "KrzysztofCwalina", + "docs/standard/events/**/**.{md,yml}": "adegeo", + "docs/standard/exceptions/**/**.{md,yml}": "gewarren", + "docs/standard/garbage-collection/**/**.{md,yml}": "gewarren", + "docs/standard/generics/**/**.{md,yml}": "adegeo", + "docs/standard/globalization-localization/**/**.{md,yml}": "adegeo", + "docs/standard/io/**/**.{md,yml}": "adegeo", + "docs/standard/library-guidance/**/**.{md,yml}": "jamesnk", + "docs/standard/linq/**/**.{md,yml}": "billwagner", + "docs/standard/memory-and-spans/**/**.{md,yml}": "gewarren", + "docs/standard/native-interop/**/**.{md,yml}": "jkoritzinsky", + "docs/standard/parallel-programming/**/**.{md,yml}": "adegeo", + "docs/standard/security/**/**.{md,yml}": "billwagner", + "docs/standard/serialization/**/**.{md,yml}": "gewarren", + "docs/standard/threading/**/**.{md,yml}": "billwagner", + "docs/standard/whats-new/**/**.{md,yml}": "gewarren", + "docs/visual-basic/**/**.{md,yml}": "billwagner", + "docs/whats-new/**/**.{md,yml}": "billwagner", "includes/**/**.md": "docs" }, "ms.author": { - "_csharplang/**/*.md": "wiwagn", - "_csharpstandard/**/*.md": "wiwagn", - "_roslyn/docs/compilers/CSharp/*.md": "wiwagn", - "_vblang/spec/*.md": "wiwagn", - "docs/ai/**/*.*": "gewarren", - "docs/architecture/**/**.md": "jamont", - "docs/architecture/grpc-for-wcf-developers/**/**.md": "jamesnk", - "docs/architecture/modernize-desktop/**/**.md": "oliag", - "docs/azure/**/*.*": "alexwolf", - "docs/orleans/**/*.*": "mosagie", - "docs/core/**/**.md": "dotnetcontent", - "docs/core/compatibility/**/**.md": "gewarren", - "docs/core/deploying/**/**.md": "adegeo", - "docs/core/diagnostics/**/**.md": "tommcdon", - "docs/core/extensions/**/**.md": "gewarren", - "docs/core/docker/**/**.md": "adegeo", - "docs/core/install/**/**.md": "adegeo", - "docs/core/native-interop/**/**.md": "jekoritz", - "docs/core/porting/**/**.md": "dotnetcontent", - "docs/core/porting/github-copilot-app-modernization/**/*.*": "adegeo", - "docs/core/project-sdk/**/**.md": "gewarren", - "docs/core/resilience/**/**.md": "gewarren", - "docs/core/runtime-config/**/**.md": "gewarren", - "docs/core/testing/**/**.md": "mosagie", - "docs/core/tools/**/**.md": "mosagie", - "docs/core/tutorials/**/**.md": "mosagie", - "docs/core/versions/**/**.md": "wiwagn", - "docs/core/whats-new/**/**.md": "wiwagn", - "docs/csharp/**/*.*": "wiwagn", - "docs/framework/**/**.md": "dotnetcontent", - "docs/framework/app-domains/**/**.md": "gewarren", - "docs/framework/configure-apps/file-schema/network/**/**.md": "ncldev", - "docs/framework/configure-apps/file-schema/winforms/**/**.md": "adegeo", - "docs/framework/deployment/**/**.md": "adegeo", - "docs/framework/get-started/**/**.md": "gewarren", - "docs/framework/install/**/**.md": "adegeo", - "docs/framework/migration-guide/**/**.md": "gewarren", - "docs/framework/misc/**/**.md": "gewarren", - "docs/framework/network-programming/**/**.md": "ncldev", - "docs/framework/performance/**/**.md": "wiwagn", - "docs/framework/reflection-and-codedom/**/**.md": "adegeo", - "docs/framework/resources/**/**.md": "adegeo", - "docs/framework/tools/**/**.md": "gewarren", - "docs/framework/ui-automation/**/**.md": "adegeo", - "docs/framework/unmanaged-api/alink/**/**.md": "jeffschw", - "docs/framework/unmanaged-api/debugging/**/**.md": "tommcdon", - "docs/framework/unmanaged-api/diagnostics/**/**.md": "tommcdon", - "docs/framework/unmanaged-api/fusion/**/**.md": "jeffschw", - "docs/framework/unmanaged-api/hosting/**/**.md": "jeffschw", - "docs/framework/unmanaged-api/profiling/**/**.md": "tommcdon", - "docs/framework/unmanaged-api/strong-naming/**/**.md": "jeffschw", - "docs/framework/unmanaged-api/tlbexp/**/**.md": "jeffschw", - "docs/framework/whats-new/**/**.md": "gewarren", - "docs/fsharp/**/**.md": "wiwagn", - "docs/fundamentals/code-analysis/**/*.md": "gewarren", - "docs/fundamentals/networking/**/**.md": "gewarren", - "docs/fundamentals/runtime-libraries/**/**.md": "gewarren", - "docs/fundamentals/syslib-diagnostics/**/**.md": "gewarren", - "docs/machine-learning/**/**.md": "gewarren", - "docs/standard/**/**.md": "gewarren", - "docs/standard/analyzers/**/**.md": "gewarren", - "docs/standard/assembly/**/**.md": "gewarren", - "docs/standard/asynchronous-programming-patterns/**/**.md": "wiwagn", - "docs/standard/attributes/**/**.md": "gewarren", - "docs/standard/base-types/**/**.md": "adegeo", - "docs/standard/collections/**/**.md": "adegeo", - "docs/standard/commandline/**/**.md": "gewarren", - "docs/standard/data/**/**.md": "gewarren", - "docs/standard/datetime/**/**.md": "adegeo", - "docs/standard/design-guidelines/**/**.md": "kcwalina", - "docs/standard/events/**/**.md": "adegeo", - "docs/standard/exceptions/**/**.md": "gewarren", - "docs/standard/garbage-collection/**/**.md": "gewarren", - "docs/standard/generics/**/**.md": "adegeo", - "docs/standard/globalization-localization/**/**.md": "dotnetcontent", - "docs/standard/io/**/**.md": "adegeo", - "docs/standard/library-guidance/**/**.md": "jamesnk", - "docs/standard/linq/**/**.md": "dotnetcontent", - "docs/standard/memory-and-spans/**/**.md": "gewarren", - "docs/standard/native-interop/**/**.md": "jekoritz", - "docs/standard/parallel-programming/**/**.md": "adegeo", - "docs/standard/security/**/**.md": "wiwagn", - "docs/standard/serialization/**/**.md": "gewarren", - "docs/standard/threading/**/**.md": "wiwagn", - "docs/standard/whats-new/**/**.md": "dotnetcontent", - "docs/visual-basic/**/**.md": "wiwagn" + "_csharplang/**/*.{md,yml}": "wiwagn", + "_csharpstandard/**/*.{md,yml}": "wiwagn", + "_roslyn/docs/compilers/CSharp/*.{md,yml}": "wiwagn", + "_vblang/spec/*.{md,yml}": "wiwagn", + "docs/ai/**/*.{md,yml}": "gewarren", + "docs/architecture/**/**.{md,yml}": "jamont", + "docs/architecture/grpc-for-wcf-developers/**/**.{md,yml}": "jamesnk", + "docs/azure/**/*.{md,yml}": "alexwolf", + "docs/orleans/**/*.{md,yml}": "mosagie", + "docs/core/**/**.{md,yml}": "dotnetcontent", + "docs/core/compatibility/**/**.{md,yml}": "gewarren", + "docs/core/deploying/**/**.{md,yml}": "adegeo", + "docs/core/diagnostics/**/**.{md,yml}": "tommcdon", + "docs/core/extensions/**/**.{md,yml}": "gewarren", + "docs/core/docker/**/**.{md,yml}": "adegeo", + "docs/core/install/**/**.{md,yml}": "adegeo", + "docs/core/native-interop/**/**.{md,yml}": "jekoritz", + "docs/core/porting/**/**.{md,yml}": "dotnetcontent", + "docs/core/porting/github-copilot-app-modernization/**/*.{md,yml}": "adegeo", + "docs/core/project-sdk/**/**.{md,yml}": "gewarren", + "docs/core/resilience/**/**.{md,yml}": "gewarren", + "docs/core/runtime-config/**/**.{md,yml}": "gewarren", + "docs/core/testing/**/**.{md,yml}": "mosagie", + "docs/core/tools/**/**.{md,yml}": "mosagie", + "docs/core/tutorials/**/**.{md,yml}": "mosagie", + "docs/core/versions/**/**.{md,yml}": "wiwagn", + "docs/core/whats-new/**/**.{md,yml}": "wiwagn", + "docs/csharp/**/*.{md,yml}": "wiwagn", + "docs/framework/**/**.{md,yml}": "dotnetcontent", + "docs/framework/app-domains/**/**.{md,yml}": "gewarren", + "docs/framework/configure-apps/file-schema/network/**/**.{md,yml}": "ncldev", + "docs/framework/configure-apps/file-schema/winforms/**/**.{md,yml}": "adegeo", + "docs/framework/deployment/**/**.{md,yml}": "adegeo", + "docs/framework/get-started/**/**.{md,yml}": "gewarren", + "docs/framework/install/**/**.{md,yml}": "adegeo", + "docs/framework/migration-guide/**/**.{md,yml}": "gewarren", + "docs/framework/misc/**/**.{md,yml}": "gewarren", + "docs/framework/network-programming/**/**.{md,yml}": "ncldev", + "docs/framework/performance/**/**.{md,yml}": "wiwagn", + "docs/framework/reflection-and-codedom/**/**.{md,yml}": "adegeo", + "docs/framework/resources/**/**.{md,yml}": "adegeo", + "docs/framework/tools/**/**.{md,yml}": "gewarren", + "docs/framework/ui-automation/**/**.{md,yml}": "adegeo", + "docs/framework/unmanaged-api/alink/**/**.{md,yml}": "jeffschw", + "docs/framework/unmanaged-api/debugging/**/**.{md,yml}": "tommcdon", + "docs/framework/unmanaged-api/diagnostics/**/**.{md,yml}": "tommcdon", + "docs/framework/unmanaged-api/fusion/**/**.{md,yml}": "jeffschw", + "docs/framework/unmanaged-api/hosting/**/**.{md,yml}": "jeffschw", + "docs/framework/unmanaged-api/profiling/**/**.{md,yml}": "tommcdon", + "docs/framework/unmanaged-api/strong-naming/**/**.{md,yml}": "jeffschw", + "docs/framework/unmanaged-api/tlbexp/**/**.{md,yml}": "jeffschw", + "docs/framework/whats-new/**/**.{md,yml}": "gewarren", + "docs/fsharp/**/**.{md,yml}": "wiwagn", + "docs/fundamentals/code-analysis/**/*.{md,yml}": "gewarren", + "docs/fundamentals/networking/**/**.{md,yml}": "gewarren", + "docs/fundamentals/runtime-libraries/**/**.{md,yml}": "gewarren", + "docs/fundamentals/syslib-diagnostics/**/**.{md,yml}": "gewarren", + "docs/machine-learning/**/**.{md,yml}": "gewarren", + "docs/standard/**/**.{md,yml}": "gewarren", + "docs/standard/analyzers/**/**.{md,yml}": "gewarren", + "docs/standard/assembly/**/**.{md,yml}": "gewarren", + "docs/standard/asynchronous-programming-patterns/**/**.{md,yml}": "wiwagn", + "docs/standard/attributes/**/**.{md,yml}": "gewarren", + "docs/standard/base-types/**/**.{md,yml}": "adegeo", + "docs/standard/collections/**/**.{md,yml}": "adegeo", + "docs/standard/commandline/**/**.{md,yml}": "gewarren", + "docs/standard/data/**/**.{md,yml}": "gewarren", + "docs/standard/datetime/**/**.{md,yml}": "adegeo", + "docs/standard/design-guidelines/**/**.{md,yml}": "kcwalina", + "docs/standard/events/**/**.{md,yml}": "adegeo", + "docs/standard/exceptions/**/**.{md,yml}": "gewarren", + "docs/standard/garbage-collection/**/**.{md,yml}": "gewarren", + "docs/standard/generics/**/**.{md,yml}": "adegeo", + "docs/standard/globalization-localization/**/**.{md,yml}": "dotnetcontent", + "docs/standard/io/**/**.{md,yml}": "adegeo", + "docs/standard/library-guidance/**/**.{md,yml}": "jamesnk", + "docs/standard/linq/**/**.{md,yml}": "dotnetcontent", + "docs/standard/memory-and-spans/**/**.{md,yml}": "gewarren", + "docs/standard/native-interop/**/**.{md,yml}": "jekoritz", + "docs/standard/parallel-programming/**/**.{md,yml}": "adegeo", + "docs/standard/security/**/**.{md,yml}": "wiwagn", + "docs/standard/serialization/**/**.{md,yml}": "gewarren", + "docs/standard/threading/**/**.{md,yml}": "wiwagn", + "docs/standard/whats-new/**/**.{md,yml}": "dotnetcontent", + "docs/visual-basic/**/**.{md,yml}": "wiwagn" }, "ms.date": { "_csharpstandard/standard/*.md": "09/12/2025", @@ -526,69 +522,69 @@ "_vblang/spec/*.md": "07/21/2017" }, "ms.subservice": { - "_csharplang/**/*.md": "lang-spec", - "_csharpstandard/**/*.md": "lang-spec", - "_roslyn/docs/compilers/CSharp/*.md": "whats-new", - "_vblang/spec/*.md": "vb-spec", - "docs/ai/**/**.md": "intelligent-apps", - "docs/architecture/blazor-for-web-forms-developers/**/**.md": "blazor", - "docs/architecture/cloud-native/**/**.md": "cloud-native", - "docs/architecture/containerized-lifecycle/**/**.md": "containerized-lifecycle", - "docs/architecture/grpc-for-wcf-developers/**/**.md": "grpc", - "docs/architecture/microservices/**/**.md": "microservices", - "docs/architecture/modernize-with-azure-containers/**/**.md": "modernize-with-azure-containers", - "docs/architecture/modern-web-apps-azure/**/**.md": "modern-web-apps-azure", - "docs/architecture/serverless/**/**.md": "serverless", - "docs/csharp/misc/**/**.md": "errors-warnings", - "docs/csharp/whats-new/**/**.md": "whats-new", - "docs/csharp/how-to/**/**.md": "fundamentals", - "docs/csharp/linq/**/**.md": "csharp-linq", - "docs/csharp/fundamentals/**/**.md": "fundamentals", - "docs/csharp/asynchronous-programming/**/**.md": "async-task-programming", - "docs/csharp/advanced-topics/**/**.md": "advanced-concepts", - "docs/csharp/language-reference/unsafe-code.md": "advanced-concepts", - "docs/csharp/programming-guide/indexers/**/**.md": "fundamentals", - "docs/csharp/programming-guide/generics/**/**.md": "fundamentals", - "docs/csharp/programming-guide/strings/**/**.md": "fundamentals", - "docs/csharp/programming-guide/types/**/**.md": "fundamentals", - "docs/csharp/programming-guide/statements-expressions-operators/**/**.md": "fundamentals", - "docs/csharp/programming-guide/exceptions/**/**.md": "fundamentals", - "docs/csharp/programming-guide/namespaces/**/**.md": "fundamentals", - "docs/csharp/programming-guide/arrays/**/**.md": "fundamentals", - "docs/csharp/programming-guide/concepts/covariance-contravariance/**/**.md": "advanced-concepts", - "docs/csharp/programming-guide/concepts/serialization/**/**.md": "fundamentals", - "docs/csharp/programming-guide/concepts/expression-trees/**/**.md": "advanced-concepts", - "docs/csharp/programming-guide/concepts/linq/**/**.md": "csharp-linq", - "docs/csharp/programming-guide/concepts/attributes/**/**.md": "fundamentals", - "docs/csharp/programming-guide/xmldoc/**/**.md": "fundamentals", - "docs/csharp/programming-guide/classes-and-structs/**/**.md": "fundamentals", - "docs/csharp/programming-guide/delegates/**/**.md": "fundamentals", - "docs/csharp/programming-guide/file-system/**/**.md": "fundamentals", - "docs/csharp/programming-guide/events/**/**.md": "fundamentals", - "docs/csharp/programming-guide/interfaces/**/**.md": "fundamentals", - "docs/csharp/tutorials/**/**.md": "fundamentals", - "docs/csharp/tutorials/exploration/**/**.md": "get-started", - "docs/csharp/tutorials/intro-to-csharp/**/**.md": "get-started", - "docs/csharp/language-reference/**/**.md": "lang-reference", - "docs/csharp/language-reference/compiler-messages/**/**.md": "errors-warnings", - "docs/csharp/roslyn-sdk/**/**.md": "roslyn-sdk", - "docs/csharp/tour-of-csharp/**/**.md": "get-started", - "docs/core/install/**/**.md": "install", - "docs/core/docker/**/**.md": "dotnet-docker", - "docs/framework/configure-apps/file-schema/network/**/**.md": "networking", - "docs/framework/configure-apps/file-schema/wcf/**/**.md": "wcf", - "docs/framework/data/adonet/**/**.md": "data-access", - "docs/framework/data/wcf/**/**.md": "wcf", - "docs/framework/docker/**/**.md": "dotnet-docker", - "docs/framework/install/**/**.md": "install-deployment", - "docs/framework/network-programming/**/**.md": "networking", - "docs/framework/wcf/**/**.md": "wcf", - "docs/framework/windows-workflow-foundation/**/**.md": "wf", - "docs/standard/analyzers/**.md": "code-analyzers", - "docs/standard/design-guidelines/*.md": "standard-library", - "docs/standard/security/**.md": "security-practices", - "docs/visual-basic/language-reference/error-messages/**/**.md": "errors-warnings", - "docs/visual-basic/misc/**/**.md": "errors-warnings" + "_csharplang/**/*.{md,yml}": "lang-spec", + "_csharpstandard/**/*.{md,yml}": "lang-spec", + "_roslyn/docs/compilers/CSharp/*.{md,yml}": "whats-new", + "_vblang/spec/*.{md,yml}": "vb-spec", + "docs/ai/**/**.{md,yml}": "intelligent-apps", + "docs/architecture/blazor-for-web-forms-developers/**/**.{md,yml}": "blazor", + "docs/architecture/cloud-native/**/**.{md,yml}": "cloud-native", + "docs/architecture/containerized-lifecycle/**/**.{md,yml}": "containerized-lifecycle", + "docs/architecture/grpc-for-wcf-developers/**/**.{md,yml}": "grpc", + "docs/architecture/microservices/**/**.{md,yml}": "microservices", + "docs/architecture/modernize-with-azure-containers/**/**.{md,yml}": "modernize-with-azure-containers", + "docs/architecture/modern-web-apps-azure/**/**.{md,yml}": "modern-web-apps-azure", + "docs/architecture/serverless/**/**.{md,yml}": "serverless", + "docs/csharp/misc/**/**.{md,yml}": "errors-warnings", + "docs/csharp/whats-new/**/**.{md,yml}": "whats-new", + "docs/csharp/how-to/**/**.{md,yml}": "fundamentals", + "docs/csharp/linq/**/**.{md,yml}": "csharp-linq", + "docs/csharp/fundamentals/**/**.{md,yml}": "fundamentals", + "docs/csharp/asynchronous-programming/**/**.{md,yml}": "async-task-programming", + "docs/csharp/advanced-topics/**/**.{md,yml}": "advanced-concepts", + "docs/csharp/language-reference/unsafe-code.{md,yml}": "advanced-concepts", + "docs/csharp/programming-guide/indexers/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/generics/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/strings/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/types/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/statements-expressions-operators/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/exceptions/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/namespaces/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/arrays/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/concepts/covariance-contravariance/**/**.{md,yml}": "advanced-concepts", + "docs/csharp/programming-guide/concepts/serialization/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/concepts/expression-trees/**/**.{md,yml}": "advanced-concepts", + "docs/csharp/programming-guide/concepts/linq/**/**.{md,yml}": "csharp-linq", + "docs/csharp/programming-guide/concepts/attributes/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/xmldoc/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/classes-and-structs/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/delegates/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/file-system/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/events/**/**.{md,yml}": "fundamentals", + "docs/csharp/programming-guide/interfaces/**/**.{md,yml}": "fundamentals", + "docs/csharp/tutorials/**/**.{md,yml}": "fundamentals", + "docs/csharp/tutorials/exploration/**/**.{md,yml}": "get-started", + "docs/csharp/tutorials/intro-to-csharp/**/**.{md,yml}": "get-started", + "docs/csharp/language-reference/**/**.{md,yml}": "lang-reference", + "docs/csharp/language-reference/compiler-messages/**/**.{md,yml}": "errors-warnings", + "docs/csharp/roslyn-sdk/**/**.{md,yml}": "roslyn-sdk", + "docs/csharp/tour-of-csharp/**/**.{md,yml}": "get-started", + "docs/core/install/**/**.{md,yml}": "install", + "docs/core/docker/**/**.{md,yml}": "dotnet-docker", + "docs/framework/configure-apps/file-schema/network/**/**.{md,yml}": "networking", + "docs/framework/configure-apps/file-schema/wcf/**/**.{md,yml}": "wcf", + "docs/framework/data/adonet/**/**.{md,yml}": "data-access", + "docs/framework/data/wcf/**/**.{md,yml}": "wcf", + "docs/framework/docker/**/**.{md,yml}": "dotnet-docker", + "docs/framework/install/**/**.{md,yml}": "install-deployment", + "docs/framework/network-programming/**/**.{md,yml}": "networking", + "docs/framework/wcf/**/**.{md,yml}": "wcf", + "docs/framework/windows-workflow-foundation/**/**.{md,yml}": "wf", + "docs/standard/analyzers/**.{md,yml}": "code-analyzers", + "docs/standard/design-guidelines/*.{md,yml}": "standard-library", + "docs/standard/security/**.{md,yml}": "security-practices", + "docs/visual-basic/language-reference/error-messages/**/**.{md,yml}": "errors-warnings", + "docs/visual-basic/misc/**/**.{md,yml}": "errors-warnings" }, "title": { "_csharpstandard/standard/README.md": "Table of contents", @@ -843,7 +839,7 @@ "_vblang/spec/overload-resolution.md": "This chapter describes the rules that govern overload resolution when multiple members have the same name." }, "titleSuffix": { - "docs/**/*.md": ".NET", + "docs/**/*.{md,yml}": ".NET", "_csharpstandard/standard/*.md": "C# language specification", "_csharplang/proposals/csharp-9.0/*.md": "C# feature specifications", "_csharplang/proposals/csharp-10.0/*.md": "C# feature specifications", @@ -852,37 +848,37 @@ "_csharplang/proposals/csharp-13.0/*.md": "C# feature specifications", "_csharplang/proposals/csharp-14.0/*.md": "C# feature specifications", "_csharplang/proposals/*.md": "C# feature specifications (preview)", - "docs/framework/**/*.md": ".NET Framework", - "docs/framework/data/adonet/**/*.md": "ADO.NET", - "docs/framework/wcf/**/*.md": "WCF", - "docs/framework/winforms/**/*.md": "Windows Forms", - "docs/framework/wpf/**/*.md": "WPF", - "docs/fsharp/tutorials/**/*.md": "F#", - "docs/fsharp/language-reference/**/*.md": "F#", - "docs/fundamentals/**/*.md": ".NET", - "docs/core/additional-tools/**.md": ".NET", - "docs/core/build/**.md": ".NET", - "docs/core/install/**.md": ".NET", - "docs/core/compatibility/**.md": ".NET", - "docs/core/deploying/**.md": ".NET", - "docs/core/docker/**.md": ".NET", - "docs/core/extensions/**.md": ".NET", - "docs/core/migration/**.md": ".NET Core", - "docs/core/porting/**.md": ".NET Core", - "docs/core/runtime-config/**.md": ".NET", - "docs/core/project-sdk/**.md": ".NET", - "docs/core/testing/**.md": ".NET", - "docs/core/tools/**.md": ".NET CLI", - "docs/core/tutorials/**.md": ".NET", - "docs/core/versions/**.md": ".NET", - "docs/csharp/**/*.md": "C#", - "docs/csharp/language-reference/**/*.md": "C# reference", - "docs/csharp/tour-of-csharp/**/*.md": "A tour of C#", - "docs/csharp/whats-new/**/*.md": "", - "docs/machine-learning/**/*.md": "ML.NET", - "docs/standard/data/sqlite/**/*.md": "Microsoft.Data.Sqlite", - "docs/standard/design-guidelines/**/*.md": "Framework Design Guidelines", - "docs/visual-basic/**/*.md": "Visual Basic" + "docs/framework/**/*.{md,yml}": ".NET Framework", + "docs/framework/data/adonet/**/*.{md,yml}": "ADO.NET", + "docs/framework/wcf/**/*.{md,yml}": "WCF", + "docs/framework/winforms/**/*.{md,yml}": "Windows Forms", + "docs/framework/wpf/**/*.{md,yml}": "WPF", + "docs/fsharp/tutorials/**/*.{md,yml}": "F#", + "docs/fsharp/language-reference/**/*.{md,yml}": "F#", + "docs/fundamentals/**/*.{md,yml}": ".NET", + "docs/core/additional-tools/**.{md,yml}": ".NET", + "docs/core/build/**.{md,yml}": ".NET", + "docs/core/install/**.{md,yml}": ".NET", + "docs/core/compatibility/**.{md,yml}": ".NET", + "docs/core/deploying/**.{md,yml}": ".NET", + "docs/core/docker/**.{md,yml}": ".NET", + "docs/core/extensions/**.{md,yml}": ".NET", + "docs/core/migration/**.{md,yml}": ".NET Core", + "docs/core/porting/**.{md,yml}": ".NET Core", + "docs/core/runtime-config/**.{md,yml}": ".NET", + "docs/core/project-sdk/**.{md,yml}": ".NET", + "docs/core/testing/**.{md,yml}": ".NET", + "docs/core/tools/**.{md,yml}": ".NET CLI", + "docs/core/tutorials/**.{md,yml}": ".NET", + "docs/core/versions/**.{md,yml}": ".NET", + "docs/csharp/**/*.{md,yml}": "C#", + "docs/csharp/language-reference/**/*.{md,yml}": "C# reference", + "docs/csharp/tour-of-csharp/**/*.{md,yml}": "A tour of C#", + "docs/csharp/whats-new/**/*.{md,yml}": "", + "docs/machine-learning/**/*.{md,yml}": "ML.NET", + "docs/standard/data/sqlite/**/*.{md,yml}": "Microsoft.Data.Sqlite", + "docs/standard/design-guidelines/**/*.{md,yml}": "Framework Design Guidelines", + "docs/visual-basic/**/*.{md,yml}": "Visual Basic" }, "open_to_public_contributors": { "docs/standard/design-guidelines/**.md": false, @@ -922,7 +918,7 @@ "docs/fsharp/language-reference/compiler-messages/**/**.{md,yml}": "3650-days", "docs/fsharp/style-guide/**/**.{md,yml}": "1095-days", "docs/fsharp/get-started/**/**.{md,yml}": "1095-days", - "docs/framework/**/*.md": "3650-days", + "docs/framework/**/*.{md,yml}": "3650-days", "docs/iot/**/**.{md,yml}": "1825-days", "docs/visual-basic/**/**.{md,yml}": "3650-days", "docs/visual-basic/whats-new/**/**.{md,yml}": "1095-days", @@ -930,11 +926,11 @@ "docs/visual-basic/developing-apps/**/**.{md,yml}": "1825-days" }, "no-loc": { - "docs/orleans/**/**.md": [ + "docs/orleans/**/**.{md,yml}": [ "Grain", "Grains" ], - "**/**.md": [ + "**/**.{md,yml}": [ "Orleans" ] } diff --git a/docs/ai/evaluation/snippets/evaluate-safety/EvaluateResponseSafety.csproj b/docs/ai/evaluation/snippets/evaluate-safety/EvaluateResponseSafety.csproj index 1b085277107d9..6698d76b405ca 100644 --- a/docs/ai/evaluation/snippets/evaluate-safety/EvaluateResponseSafety.csproj +++ b/docs/ai/evaluation/snippets/evaluate-safety/EvaluateResponseSafety.csproj @@ -11,13 +11,13 @@ - - - + + + - - + + diff --git a/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj b/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj index bef5bd1ec4ebe..52caa2c5268f5 100644 --- a/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj +++ b/docs/ai/evaluation/snippets/evaluate-with-reporting/TestAIWithReporting.csproj @@ -11,13 +11,13 @@ - - - - + + + + - - + + diff --git a/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj index d539e69ea57b8..be3f21fb7bb49 100644 --- a/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj +++ b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/docs/ai/includes/sk-connectors.md b/docs/ai/includes/sk-connectors.md index 74b6b3c2abbae..c0402ca11d34a 100644 --- a/docs/ai/includes/sk-connectors.md +++ b/docs/ai/includes/sk-connectors.md @@ -1,6 +1,4 @@ --- -author: alexwolfmsft -ms.author: alexwolf ms.date: 07/29/2024 ms.topic: include --- diff --git a/docs/ai/media/build-mcp-server/add-custom-mcp-server-http.png b/docs/ai/media/build-mcp-server/add-custom-mcp-server-http.png new file mode 100644 index 0000000000000..28a8c8e47c9f6 Binary files /dev/null and b/docs/ai/media/build-mcp-server/add-custom-mcp-server-http.png differ diff --git a/docs/ai/media/build-mcp-server/add-mcp-server-config-target.png b/docs/ai/media/build-mcp-server/add-mcp-server-config-target.png new file mode 100644 index 0000000000000..90b8e0b000968 Binary files /dev/null and b/docs/ai/media/build-mcp-server/add-mcp-server-config-target.png differ diff --git a/docs/ai/media/build-mcp-server/add-mcp-server-select-type.png b/docs/ai/media/build-mcp-server/add-mcp-server-select-type.png new file mode 100644 index 0000000000000..0516c584217df Binary files /dev/null and b/docs/ai/media/build-mcp-server/add-mcp-server-select-type.png differ diff --git a/docs/ai/media/build-mcp-server/additional-information-new-mcp-server.png b/docs/ai/media/build-mcp-server/additional-information-new-mcp-server.png new file mode 100644 index 0000000000000..405638e5073b1 Binary files /dev/null and b/docs/ai/media/build-mcp-server/additional-information-new-mcp-server.png differ diff --git a/docs/ai/media/build-mcp-server/cli-mcp-server-template-options.png b/docs/ai/media/build-mcp-server/cli-mcp-server-template-options.png new file mode 100644 index 0000000000000..a53817b338861 Binary files /dev/null and b/docs/ai/media/build-mcp-server/cli-mcp-server-template-options.png differ diff --git a/docs/ai/media/build-mcp-server/create-new-project-mcp-server-app.png b/docs/ai/media/build-mcp-server/create-new-project-mcp-server-app.png new file mode 100644 index 0000000000000..c4f771ad81583 Binary files /dev/null and b/docs/ai/media/build-mcp-server/create-new-project-mcp-server-app.png differ diff --git a/docs/ai/media/build-mcp-server/mcp-server-stdio-project-structure.png b/docs/ai/media/build-mcp-server/mcp-server-stdio-project-structure.png new file mode 100644 index 0000000000000..8931c6e82f141 Binary files /dev/null and b/docs/ai/media/build-mcp-server/mcp-server-stdio-project-structure.png differ diff --git a/docs/ai/media/build-mcp-server/naming-mcp-server-project.png b/docs/ai/media/build-mcp-server/naming-mcp-server-project.png new file mode 100644 index 0000000000000..cd203d38bc143 Binary files /dev/null and b/docs/ai/media/build-mcp-server/naming-mcp-server-project.png differ diff --git a/docs/ai/media/build-mcp-server/start-window-create-new-project.png b/docs/ai/media/build-mcp-server/start-window-create-new-project.png new file mode 100644 index 0000000000000..4e2eea01816bc Binary files /dev/null and b/docs/ai/media/build-mcp-server/start-window-create-new-project.png differ diff --git a/docs/ai/media/build-mcp-server/vs-add-custom-mcp-server.png b/docs/ai/media/build-mcp-server/vs-add-custom-mcp-server.png new file mode 100644 index 0000000000000..2fc91bd59e56b Binary files /dev/null and b/docs/ai/media/build-mcp-server/vs-add-custom-mcp-server.png differ diff --git a/docs/ai/media/build-mcp-server/vs-mcp-server-project-structure.png b/docs/ai/media/build-mcp-server/vs-mcp-server-project-structure.png new file mode 100644 index 0000000000000..e3bf56358297c Binary files /dev/null and b/docs/ai/media/build-mcp-server/vs-mcp-server-project-structure.png differ diff --git a/docs/ai/media/build-mcp-server/vs-mcp-tools-list.png b/docs/ai/media/build-mcp-server/vs-mcp-tools-list.png new file mode 100644 index 0000000000000..337bfe28b407f Binary files /dev/null and b/docs/ai/media/build-mcp-server/vs-mcp-tools-list.png differ diff --git a/docs/ai/media/build-mcp-server/vs-mcp-tools-popup.png b/docs/ai/media/build-mcp-server/vs-mcp-tools-popup.png new file mode 100644 index 0000000000000..d895db7c7757f Binary files /dev/null and b/docs/ai/media/build-mcp-server/vs-mcp-tools-popup.png differ diff --git a/docs/ai/media/build-mcp-server/vscode-command-palette-dotnet-projects.png b/docs/ai/media/build-mcp-server/vscode-command-palette-dotnet-projects.png new file mode 100644 index 0000000000000..a34c2679f8ea4 Binary files /dev/null and b/docs/ai/media/build-mcp-server/vscode-command-palette-dotnet-projects.png differ diff --git a/docs/ai/media/build-mcp-server/vscode-create-new-mcp-server-project.png b/docs/ai/media/build-mcp-server/vscode-create-new-mcp-server-project.png new file mode 100644 index 0000000000000..610e2531e345a Binary files /dev/null and b/docs/ai/media/build-mcp-server/vscode-create-new-mcp-server-project.png differ diff --git a/docs/ai/media/build-mcp-server/vscode-mcp-server-template-options.png b/docs/ai/media/build-mcp-server/vscode-mcp-server-template-options.png new file mode 100644 index 0000000000000..5d8bb44e68070 Binary files /dev/null and b/docs/ai/media/build-mcp-server/vscode-mcp-server-template-options.png differ diff --git a/docs/ai/media/build-mcp-server/vscode-mcp-tools-list.png b/docs/ai/media/build-mcp-server/vscode-mcp-tools-list.png new file mode 100644 index 0000000000000..df2812c0fb223 Binary files /dev/null and b/docs/ai/media/build-mcp-server/vscode-mcp-tools-list.png differ diff --git a/docs/ai/media/build-mcp-server/vscode-naming-mcp-server.png b/docs/ai/media/build-mcp-server/vscode-naming-mcp-server.png new file mode 100644 index 0000000000000..8c904a7efb579 Binary files /dev/null and b/docs/ai/media/build-mcp-server/vscode-naming-mcp-server.png differ diff --git a/docs/ai/quickstarts/ai-templates.md b/docs/ai/quickstarts/ai-templates.md index c0088374eb5a5..614ec12ddffcf 100644 --- a/docs/ai/quickstarts/ai-templates.md +++ b/docs/ai/quickstarts/ai-templates.md @@ -3,8 +3,6 @@ title: Quickstart - Create a .NET AI app using the AI app template description: Create a .NET AI app to chat with custom data using the AI app template extensions and the Microsoft.Extensions.AI libraries ms.date: 07/30/2025 ms.topic: quickstart -author: alexwolfmsft -ms.author: alexwolf zone_pivot_groups: meai-targets --- diff --git a/docs/ai/quickstarts/build-mcp-server.md b/docs/ai/quickstarts/build-mcp-server.md index 7879b4ee05c82..d3782e1694888 100644 --- a/docs/ai/quickstarts/build-mcp-server.md +++ b/docs/ai/quickstarts/build-mcp-server.md @@ -5,24 +5,91 @@ ms.date: 10/20/2025 ms.topic: quickstart author: alexwolfmsft ms.author: alexwolf +zone_pivot_groups: development-environment-one --- # Create a minimal MCP server using C# and publish to NuGet -In this quickstart, you create a minimal Model Context Protocol (MCP) server using the [C# SDK for MCP](https://github.com/modelcontextprotocol/csharp-sdk), connect to it using GitHub Copilot, and publish it to NuGet. MCP servers are services that expose capabilities to clients through the Model Context Protocol (MCP). +In this quickstart, you create a minimal Model Context Protocol (MCP) server using the [C# SDK for MCP](https://github.com/modelcontextprotocol/csharp-sdk), connect to it using GitHub Copilot, and publish it to NuGet (stdio transport only). MCP servers are services that expose capabilities to clients through the Model Context Protocol (MCP). > [!NOTE] > The `Microsoft.McpServer.ProjectTemplates` template package is currently in preview. ## Prerequisites -- [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet) (preview 6 or higher) -- [Visual Studio Code](https://code.visualstudio.com/) +::: zone pivot="visualstudio" + +- [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet) +- [Visual Studio 2022 or higher](https://visualstudio.microsoft.com/) +- [GitHub Copilot](https://github.com/features/copilot) +- [NuGet.org account](https://www.nuget.org/users/account/LogOn) + +::: zone-end + +::: zone pivot="vscode" + +- [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet) +- [Visual Studio Code](https://code.visualstudio.com/) (optional) +- [C# Dev Kit extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) - [GitHub Copilot extension](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) for Visual Studio Code - [NuGet.org account](https://www.nuget.org/users/account/LogOn) +::: zone-end + +::: zone pivot="cli" + +- [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet) +- [Visual Studio Code](https://code.visualstudio.com/) (optional) +- [Visual Studio](https://visualstudio.microsoft.com/) (optional) +- [GitHub Copilot](https://github.com/features/copilot) / [GitHub Copilot extension](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) for Visual Studio Code +- [NuGet.org account](https://www.nuget.org/users/account/LogOn) + +::: zone-end + ## Create the project +::: zone pivot="visualstudio" + +1. In a terminal window, install the MCP Server template: + + ```dotnetcli + dotnet new install Microsoft.McpServer.ProjectTemplates + ``` + + > [!NOTE] + > .NET 10.0 SDK or a later version is required to install `Microsoft.McpServer.ProjectTemplates`. + +1. Open Visual Studio, and select **Create a new project** in the start window (or select **File** > **New** > **Project/Solution** from inside Visual Studio). + + ![Create a new project dialog window](../media/build-mcp-server/start-window-create-new-project.png) + +1. In the **Create a new project** window, select **C#** from the Language list and **AI** from the **All project types** list. After you apply the language and project type filters, select the **MCP Server App** template, and then select **Next**. + + ![Create a new MCP Server app project in project dialog window](../media/build-mcp-server/create-new-project-mcp-server-app.png) + +1. In the **Configure your new project** window, enter **MyMcpServer** in the **Project name** field. Then, select **Next**. + + ![Name your new MCP Server app project in the Configure your new project dialog window](../media/build-mcp-server/naming-mcp-server-project.png) + +1. In the **Additional information** window, you can configure the following options: + + - **Framework**: Select the target .NET framework. + - **MCP Server Transport Type**: Choose between creating a **local** (stdio) or a **remote** (http) MCP server. + - **Enable native AOT (Ahead-Of-Time) publish**: Enable your MCP server to be self-contained and compiled to native code. For more information, see the [Native AOT deployment guide](../../core/deploying/native-aot/index.md). + - **Enable self-contained publish**: Enable your MCP server to be published as a self-contained executable. For more information, see the [Self-contained deployment section of the .NET application publishing guide](../../core/deploying/index.md#self-contained-deployment). + + Choose your preferred options or keep the default ones, and then select **Create**. + + ![Select additional options including framework and transport for your MCP server](../media/build-mcp-server/additional-information-new-mcp-server.png) + + Visual Studio opens your new project. + +1. Update the `` in the `.csproj` file to be unique on NuGet.org, for example `.SampleMcpServer`. + +::: zone-end + +::: zone pivot="vscode" + 1. In a terminal window, install the MCP Server template: ```bash @@ -30,7 +97,45 @@ In this quickstart, you create a minimal Model Context Protocol (MCP) server usi ``` > [!NOTE] - > .NET 10.0 SDK (Preview 6 or later) is required to install `Microsoft.McpServer.ProjectTemplates`. + > .NET 10.0 SDK or later is required to install `Microsoft.McpServer.ProjectTemplates`. + +1. Open Visual Studio Code. + +1. Go to the **Explorer** view and select **Create .NET Project**. Alternatively, you can bring up the Command Palette using Ctrl+Shift+P (Command+Shift+P on MacOS) and then type ".NET" to find and select the **.NET: New Project** command. + + This action will bring up a dropdown list of .NET projects. + + ![Dropdown list of .NET projects](../media/build-mcp-server/vscode-command-palette-dotnet-projects.png) + +1. After selecting the command, use the Search bar in the Command Palette or scroll down to locate the **MCP Server App** template. + + ![Create an MCP Server App template](../media/build-mcp-server/vscode-create-new-mcp-server-project.png) + +1. Select the location where you would like the new project to be created. + +1. Give your new project a name, **MyMCPServer**. Press **Enter**. + ![Name your MCP Server](../media/build-mcp-server/vscode-naming-mcp-server.png) + +1. Select your solution file format (`.sln` or `.slnx`). + +1. Select **Template Options**. Here, you can configure the following options: + + - **Framework**: Select the target .NET framework. + - **MCP Server Transport Type**: Choose between creating a **local** (stdio) or a **remote** (http) MCP server. + - **Enable native AOT (Ahead-Of-Time) publish**: Enable your MCP server to be self-contained and compiled to native code. For more information, see the [Native AOT deployment guide](../../core/deploying/native-aot/index.md). + - **Enable self-contained publish**: Enable your MCP server to be published as a self-contained executable. For more information, see the [Self-contained deployment section of the .NET application publishing guide](../../core/deploying/index.md#self-contained-deployment). + + ![MCP Server Template Options](../media/build-mcp-server/vscode-mcp-server-template-options.png) + + Choose your preferred options or keep the default ones, and then select **Create Project**. + + VS Code opens your new project. + +1. Update the `` in the `.csproj` file to be unique on NuGet.org, for example `.SampleMcpServer`. + +::: zone-end + +::: zone pivot="cli" 1. Create a new MCP server app with the `dotnet new mcpserver` command: @@ -40,6 +145,15 @@ In this quickstart, you create a minimal Model Context Protocol (MCP) server usi By default, this command creates a self-contained tool package targeting all of the most common platforms that .NET is supported on. To see more options, use `dotnet new mcpserver --help`. + Using the `dotnet new mcpserver --help` command gives you several template options you can add when creating a new MCP server: + + - **Framework**: Select the target .NET framework. + - **MCP Server Transport Type**: Choose between creating a **local** (stdio) or a **remote** (http) MCP server. + - **Enable native AOT (Ahead-Of-Time) publish**: Enable your MCP server to be self-contained and compiled to native code. For more information, see the [Native AOT deployment guide](../../core/deploying/native-aot/index.md). + - **Enable self-contained publish**: Enable your MCP server to be published as a self-contained executable. For more information, see the [Self-contained deployment section of the .NET application publishing guide](../../core/deploying/index.md#self-contained-deployment). + + ![Template options for an MCP Server in .NET CLI](../media/build-mcp-server/cli-mcp-server-template-options.png) + 1. Navigate to the `SampleMcpServer` directory: ```bash @@ -54,11 +168,160 @@ In this quickstart, you create a minimal Model Context Protocol (MCP) server usi 1. Update the `` in the `.csproj` file to be unique on NuGet.org, for example `.SampleMcpServer`. -## Configure the MCP server in Visual Studio Code +::: zone-end + +## Tour the MCP Server Project + +Creating your MCP server project via the template gives you the following major files: + +* `Program.cs`: A file defining the application as an MCP server and registering MCP services such as transport type and MCP tools. + * Choosing the (default) **stdio** transport option in when creating the project, this file will be configured to define the MCP Server as a local one (that is, `.withStdioServerTransport()`). + * Choosing the **http** transport option will configure this file to include remote transport-specific definitions (that is, `.withHttpServerTransport()`, `MapMcp()`). +* `RandomNumberTools.cs`: A class defining an example MCP server tool that returns a random number between user-specified min/max values. +* **[HTTP Transport Only]** `[MCPServerName].http`: A file defining the default host address for an HTTP MCP server and JSON-RPC communication. +* `server.json`: A file defining how and where your MCP server is published. + +::: zone pivot="visualstudio" + +![MCP Server Project Structure (stdio)](../media/build-mcp-server/vs-mcp-server-project-structure.png) + +::: zone-end + +::: zone pivot="cli,vscode" + +![MCP Server Project Structure (stdio)](../media/build-mcp-server/mcp-server-stdio-project-structure.png) + +::: zone-end -Configure GitHub Copilot for Visual Studio Code to use your custom MCP server: +## Configure the MCP server + +::: zone pivot="visualstudio" + +Configure GitHub Copilot for Visual Studio to use your custom MCP server. + +1. In Visual Studio, select the GitHub Copilot icon in the top right corner and select **Open Chat Window**. + +1. In the GitHub Copilot Chat window, click the **Select Tools** wrench icon followed by the plus icon in the top right corner. + + ![Select MCP Tools window and Plus Icon](../media/build-mcp-server/vs-mcp-tools-popup.png) + +1. In the **Add Custom MCP Server** dialog window, enter the following info: + + * **Destination**: Choose the scope of where your MCP server is configured: + * **Solution** - The MCP server is available only across the active solution. + * **Global** - The MCP server is available across all solutions. + * **Server ID**: The unique name / identifier for your MCP server. + * **Type**: The transport type of your MCP server (stdio or HTTP). + * **Command (Stdio transport only)**: The command to run your stdio MCP server (that is, `dotnet run --project [relative path to .csproj file]`) + * **URL (HTTP transport only)**: The address of your HTTP MCP server + * **Environment Variables (optional)** + + ![Add Custom MCP Server dialog window](../media/build-mcp-server/vs-add-custom-mcp-server.png) + +1. Select **Save**. A `.mcp.json` file will be added to the specified destination. + +**Stdio Transport `.mcp.json`** + +Add the relative path to your `.csproj` file under the "args" field. + + ```json + { + "inputs": [], + "servers": { + "MyMcpServer": { + "type": "stdio", + "command": "dotnet", + "args": [ + "run", + "--project", + "" + ] + } + } + } + ``` + +**HTTP Transport `.mcp.json`** + + ```json + { + "inputs": [], + "servers": { + "MyMCPServer": { + "url": "http://localhost:6278", + "type": "http", + "headers": {} + } + } + } + ``` + +::: zone-end + +::: zone pivot="vscode,cli" + +Configure GitHub Copilot for Visual Studio Code to use your custom MCP server, either via the VS Code Command Palette or manually. + +### Command Palette configuration + +1. Open the Command Palette using Ctrl+Shift+P (Command+Shift+P on macOS). Search "mcp" to locate the `MCP: Add Server` command. + +1. Select the type of MCP server to add (typically the transport type you selected at project creation). + + ![Select the MCP server type to add via Command Palette](../media/build-mcp-server/add-mcp-server-select-type.png) + +1. If adding a **stdio** MCP server, enter a command and optional arguments. For this example, use `dotnet run --project`. + + If adding an **HTTP** MCP server, enter the localhost or web address. + +1. Enter a unique server ID (example: "MyMCPServer"). + +1. Select a configuration target: + + * **Global**: Make the MCP server available across all workspaces. The generated `mcp.json` file will appear under your global user configuration. + + * **Workspace**: Make the MCP server available only from within the current workspace. The generated `mcp.json` file will appear under the `.vscode` folder within your workspace. + + ![Add configuration target for MCP server](../media/build-mcp-server/add-mcp-server-config-target.png) + +1. After you complete the previous steps, an `.mcp.json` file will be created in the location specified by the configuration target. + +**Stdio Transport `mcp.json`** + +Add the relative path to your `.csproj` file under the "args" field. + + ```json + { + "servers": { + "MyMcpServer": { + "type": "stdio", + "command": "dotnet", + "args": [ + "run", + "--project", + "" + ] + } + } + } + ``` + +**HTTP Transport `mcp.json`** + + ```json + { + "servers": { + "MyMCPServer": { + "url": "http://localhost:6278", + "type": "http" + } + }, + "inputs": [] + } + ``` + +### Manual configuration -1. If you haven't already, open your project folder in Visual Studio Code. 1. Create a `.vscode` folder at the root of your project. 1. Add an `mcp.json` file in the `.vscode` folder with the following content: @@ -83,15 +346,19 @@ Configure GitHub Copilot for Visual Studio Code to use your custom MCP server: 1. Save the file. +::: zone-end + ## Test the MCP server +::: zone pivot="visualstudio" + The MCP server template includes a tool called `get_random_number` you can use for testing and as a starting point for development. -1. Open GitHub Copilot in Visual Studio Code and switch to agent mode. +1. Open GitHub Copilot chat in Visual Studio and switch to **Agent** mode. -1. Select the **Select tools** icon to verify your **SampleMcpServer** is available with the sample tool listed. +1. Select the **Select tools** icon to verify your **MyMCPServer** is available with the sample tool listed. - :::image type="content" source="../media/mcp/available-tools-nuget.png" alt-text="A screenshot showing the available MCP tools."::: + ![MCP Tools List in GitHub Copilot Chat](../media/build-mcp-server/vs-mcp-tools-list.png) 1. Enter a prompt to run the **get_random_number** tool: @@ -102,8 +369,8 @@ The MCP server template includes a tool called `get_random_number` you can use f 1. GitHub Copilot requests permission to run the **get_random_number** tool for your prompt. Select **Continue** or use the arrow to select a more specific behavior: - **Current session** always runs the operation in the current GitHub Copilot Agent Mode session. - - **Current workspace** always runs the command for the current Visual Studio Code workspace. - - **Always allow** sets the operation to always run for any GitHub Copilot Agent Mode session or any Visual Studio Code workspace. + - **Current solution** always runs the command for the current VS solution. + - **Always allow** sets the operation to always run for any GitHub Copilot Agent Mode session. 1. Verify that the server responds with a random number: @@ -111,6 +378,38 @@ The MCP server template includes a tool called `get_random_number` you can use f Your random number is 42. ``` +::: zone-end + +::: zone pivot="vscode,cli" + +The MCP server template includes a tool called `get_random_number` you can use for testing and as a starting point for development. + +1. Open GitHub Copilot chat in VS Code and switch to **Agent** mode. + +1. Select the **Select tools** icon to verify your **MyMCPServer** is available with the sample tool listed. + + ![MCP Tools List in GitHub Copilot Chat](../media/build-mcp-server/vscode-mcp-tools-list.png) + +1. Enter a prompt to run the **get_random_number** tool: + + ```console + Give me a random number between 1 and 100. + ``` + +1. GitHub Copilot requests permission to run the **get_random_number** tool for your prompt. Select **Continue** or use the arrow to select a more specific behavior: + + - **Current session** always runs the operation in the current GitHub Copilot Agent Mode session. + - **Current workspace** always runs the command for the current VS Code workspace. + - **Always allow** sets the operation to always run for any GitHub Copilot Agent Mode session. + +1. Verify that the server responds with a random number: + + ```output + Your random number is 42. + ``` + +::: zone-end + ## Add inputs and configuration options In this example, you enhance the MCP server to use a configuration value set in an environment variable. This could be configuration needed for the functioning of your MCP server, such as an API key, an endpoint to connect to, or a local directory path. diff --git a/docs/ai/quickstarts/includes/ai-templates-azure-openai.md b/docs/ai/quickstarts/includes/ai-templates-azure-openai.md index 68ba085fecac1..7c0060d4b43ee 100644 --- a/docs/ai/quickstarts/includes/ai-templates-azure-openai.md +++ b/docs/ai/quickstarts/includes/ai-templates-azure-openai.md @@ -1,8 +1,6 @@ --- ms.date: 2/21/2025 -ms.topic: quickstart -author: alexwolfmsft -ms.author: alexwolf +ms.topic: include --- ## Prerequisites diff --git a/docs/ai/quickstarts/includes/ai-templates-github-models.md b/docs/ai/quickstarts/includes/ai-templates-github-models.md index 226e1b1ada8db..b477bcf3514b2 100644 --- a/docs/ai/quickstarts/includes/ai-templates-github-models.md +++ b/docs/ai/quickstarts/includes/ai-templates-github-models.md @@ -1,8 +1,6 @@ --- ms.date: 2/21/2025 ms.topic: include -author: alexwolfmsft -ms.author: alexwolf --- ## Prerequisites diff --git a/docs/ai/quickstarts/includes/ai-templates-ollama.md b/docs/ai/quickstarts/includes/ai-templates-ollama.md index 9412de9fb0e9e..0f1444658272b 100644 --- a/docs/ai/quickstarts/includes/ai-templates-ollama.md +++ b/docs/ai/quickstarts/includes/ai-templates-ollama.md @@ -1,8 +1,6 @@ --- ms.date: 2/21/2025 -ms.topic: quickstart -author: alexwolfmsft -ms.author: alexwolf +ms.topic: include --- ## Prerequisites diff --git a/docs/ai/quickstarts/includes/ai-templates-openai.md b/docs/ai/quickstarts/includes/ai-templates-openai.md index e26fe93ac26cc..73a2004c708e0 100644 --- a/docs/ai/quickstarts/includes/ai-templates-openai.md +++ b/docs/ai/quickstarts/includes/ai-templates-openai.md @@ -1,8 +1,6 @@ --- ms.date: 2/21/2025 ms.topic: include -author: alexwolfmsft -ms.author: alexwolf --- ## Prerequisites diff --git a/docs/ai/quickstarts/snippets/function-calling/openai/FunctionCallingAI.csproj b/docs/ai/quickstarts/snippets/function-calling/openai/FunctionCallingAI.csproj index 72ba3b661fe4a..b107e8ab57307 100644 --- a/docs/ai/quickstarts/snippets/function-calling/openai/FunctionCallingAI.csproj +++ b/docs/ai/quickstarts/snippets/function-calling/openai/FunctionCallingAI.csproj @@ -8,10 +8,10 @@ - + - - + + diff --git a/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj b/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj index 9cdb68e0563d5..a7aa8e1a67f8f 100644 --- a/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj +++ b/docs/ai/quickstarts/snippets/image-generation/openai/ImagesOpenAI.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/docs/ai/snippets/microsoft-extensions-ai/AI.Shared/AI.Shared.csproj b/docs/ai/snippets/microsoft-extensions-ai/AI.Shared/AI.Shared.csproj index f4b8718cc9f11..c1ef30aab2a4a 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/AI.Shared/AI.Shared.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/AI.Shared/AI.Shared.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CustomEmbeddingsMiddle/ConsoleAI.CustomEmbeddingsMiddle.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CustomEmbeddingsMiddle/ConsoleAI.CustomEmbeddingsMiddle.csproj index ee773dd158c8d..2f466c2fa9730 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CustomEmbeddingsMiddle/ConsoleAI.CustomEmbeddingsMiddle.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CustomEmbeddingsMiddle/ConsoleAI.CustomEmbeddingsMiddle.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj index 61850fb928057..4d6f39628314d 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.DependencyInjection/ConsoleAI.DependencyInjection.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.StatelessStateful/ConsoleAI.StatelessStateful.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.StatelessStateful/ConsoleAI.StatelessStateful.csproj index 7e9785c3a2ae3..ccf51af65d5f9 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.StatelessStateful/ConsoleAI.StatelessStateful.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.StatelessStateful/ConsoleAI.StatelessStateful.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.UseExample/ConsoleAI.UseExample.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.UseExample/ConsoleAI.UseExample.csproj index 69e1dda850abc..dff59fde41a1c 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.UseExample/ConsoleAI.UseExample.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.UseExample/ConsoleAI.UseExample.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/ai/tutorials/tutorial-ai-vector-search.md b/docs/ai/tutorials/tutorial-ai-vector-search.md index 41553e0a5b8cf..4d712d9624b20 100644 --- a/docs/ai/tutorials/tutorial-ai-vector-search.md +++ b/docs/ai/tutorials/tutorial-ai-vector-search.md @@ -13,7 +13,7 @@ This tutorial explores integration of the RAG pattern using Open AI models and v ## Prerequisites -- [.NET 8.0 installed](https://dotnet.microsoft.com/) +- [.NET 8.0](https://dotnet.microsoft.com/) - An [Azure Account](https://azure.microsoft.com/free) - An [Azure Cosmos DB for MongoDB vCore](/azure/cosmos-db/mongodb/vcore/introduction) service - An [Azure Open AI](/azure/ai-services/openai/overview) service diff --git a/docs/azure/azure-tools.md b/docs/azure/azure-tools.md index b8dd99793553d..a6528d4d86067 100644 --- a/docs/azure/azure-tools.md +++ b/docs/azure/azure-tools.md @@ -4,8 +4,6 @@ description: This article describes additional tools and utilities for working w ms.topic: concept-article ms.custom: devx-track-dotnet, engagement-fy23, devx-track-azurepowershell ms.date: 8/15/2024 -author: alexwolfmsft -ms.author: alexwolf --- # Additional Tools for Azure Developers diff --git a/docs/azure/configure-visual-studio.md b/docs/azure/configure-visual-studio.md index 1d1163733eaeb..a2424595578af 100644 --- a/docs/azure/configure-visual-studio.md +++ b/docs/azure/configure-visual-studio.md @@ -4,8 +4,6 @@ description: This article helps you configure Visual Studio for Azure developmen ms.topic: concept-article ms.custom: devx-track-dotnet, engagement-fy23 ms.date: 3/20/2025 -author: alexwolfmsft -ms.author: alexwolf --- # Configure Visual Studio for Azure development with .NET diff --git a/docs/azure/configure-vs-code.md b/docs/azure/configure-vs-code.md index 85c5fcae063f2..247d7434f4a5f 100644 --- a/docs/azure/configure-vs-code.md +++ b/docs/azure/configure-vs-code.md @@ -3,8 +3,6 @@ title: Configure Visual Studio Code for Azure development with .NET description: This article helps you configure Visual Studio Code for Azure development including getting the right plugins installed and configured in VS Code ms.topic: concept-article ms.date: 8/15/2024 -author: alexwolfmsft -ms.author: alexwolf ms.custom: - devx-track-dotnet - vscode-azure-extension-update-completed diff --git a/docs/azure/create-azure-account.md b/docs/azure/create-azure-account.md index f4a2e6adc466e..acf6970ac702a 100644 --- a/docs/azure/create-azure-account.md +++ b/docs/azure/create-azure-account.md @@ -4,8 +4,6 @@ description: To use Azure, you need an Azure account. This article covers the t ms.topic: concept-article ms.custom: devx-track-dotnet, engagement-fy23 ms.date: 8/15/2024 -author: alexwolfmsft -ms.author: alexwolf --- # Create an Azure account diff --git a/docs/azure/includes/dotnet-all.md b/docs/azure/includes/dotnet-all.md index 5651a21711f1c..a4254c6378c2c 100644 --- a/docs/azure/includes/dotnet-all.md +++ b/docs/azure/includes/dotnet-all.md @@ -81,7 +81,7 @@ | OpenAI Assistants | NuGet [1.0.0-beta.4](https://www.nuget.org/packages/Azure.AI.OpenAI.Assistants/1.0.0-beta.4) | [docs](/dotnet/api/overview/azure/AI.OpenAI.Assistants-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.4](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.OpenAI.Assistants_1.0.0-beta.4/sdk/openai/Azure.AI.OpenAI.Assistants/) | | OpenAI Inference | NuGet [2.1.0](https://www.nuget.org/packages/Azure.AI.OpenAI/2.1.0)
NuGet [2.8.0-beta.1](https://www.nuget.org/packages/Azure.AI.OpenAI/2.8.0-beta.1) | [docs](/dotnet/api/overview/azure/AI.OpenAI-readme) | GitHub [2.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.OpenAI_2.1.0/sdk/openai/Azure.AI.OpenAI/)
GitHub [2.8.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.OpenAI_2.8.0-beta.1/sdk/openai/Azure.AI.OpenAI/) | | OpenTelemetry AspNetCore | NuGet [1.4.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.AspNetCore/1.4.0) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.AspNetCore-readme) | GitHub [1.4.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.AspNetCore_1.4.0/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/) | -| OpenTelemetry Exporter | NuGet [1.5.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.5.0)
NuGet [1.6.0-beta.1](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.6.0-beta.1) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.Exporter-readme) | GitHub [1.5.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.5.0/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/)
GitHub [1.6.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.6.0-beta.1/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/) | +| OpenTelemetry Exporter | NuGet [1.5.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.5.0)
NuGet [1.6.0-beta.2](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.6.0-beta.2) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.Exporter-readme) | GitHub [1.5.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.5.0/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/)
GitHub [1.6.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.6.0-beta.2/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/) | | Personalizer | NuGet [2.0.0-beta.2](https://www.nuget.org/packages/Azure.AI.Personalizer/2.0.0-beta.2) | [docs](/dotnet/api/overview/azure/AI.Personalizer-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [2.0.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.Personalizer_2.0.0-beta.2/sdk/personalizer/Azure.AI.Personalizer/) | | Playwright | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Developer.Playwright/1.0.0) | [docs](/dotnet/api/overview/azure/Developer.Playwright-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright_1.0.0/sdk/loadtestservice/Azure.Developer.Playwright/) | | Playwright NUnit | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Developer.Playwright.NUnit/1.0.0) | [docs](/dotnet/api/overview/azure/Developer.Playwright.NUnit-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright.NUnit_1.0.0/sdk/loadtestservice/Azure.Developer.Playwright.NUnit/) | @@ -214,7 +214,7 @@ | Resource Management - Confidential Ledger | NuGet [1.0.1](https://www.nuget.org/packages/Azure.ResourceManager.ConfidentialLedger/1.0.1)
NuGet [1.1.0-beta.6](https://www.nuget.org/packages/Azure.ResourceManager.ConfidentialLedger/1.1.0-beta.6) | [docs](/dotnet/api/overview/azure/ResourceManager.ConfidentialLedger-readme) | GitHub [1.0.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConfidentialLedger_1.0.1/sdk/confidentialledger/Azure.ResourceManager.ConfidentialLedger/)
GitHub [1.1.0-beta.6](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConfidentialLedger_1.1.0-beta.6/sdk/confidentialledger/Azure.ResourceManager.ConfidentialLedger/) | | Resource Management - Confluent | NuGet [1.2.1](https://www.nuget.org/packages/Azure.ResourceManager.Confluent/1.2.1) | [docs](/dotnet/api/overview/azure/ResourceManager.Confluent-readme) | GitHub [1.2.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Confluent_1.2.1/sdk/confluent/Azure.ResourceManager.Confluent/) | | Resource Management - Connected VMware vSphere | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.ConnectedVMwarevSphere/1.1.1) | [docs](/dotnet/api/overview/azure/ResourceManager.ConnectedVMwarevSphere-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConnectedVMwarevSphere_1.1.1/sdk/connectedvmwarevsphere/Azure.ResourceManager.ConnectedVMwarevSphere/) | -| Resource Management - Connectedcache | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.ResourceManager.ConnectedCache/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/ResourceManager.ConnectedCache-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConnectedCache_1.0.0-beta.1/sdk/connectedcache/Azure.ResourceManager.ConnectedCache/) | +| Resource Management - Connectedcache | NuGet [1.0.0-beta.2](https://www.nuget.org/packages/Azure.ResourceManager.ConnectedCache/1.0.0-beta.2) | [docs](/dotnet/api/overview/azure/ResourceManager.ConnectedCache-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConnectedCache_1.0.0-beta.2/sdk/connectedcache/Azure.ResourceManager.ConnectedCache/) | | Resource Management - Consumption | NuGet [1.0.1](https://www.nuget.org/packages/Azure.ResourceManager.Consumption/1.0.1)
NuGet [1.1.0-beta.3](https://www.nuget.org/packages/Azure.ResourceManager.Consumption/1.1.0-beta.3) | [docs](/dotnet/api/overview/azure/ResourceManager.Consumption-readme) | GitHub [1.0.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Consumption_1.0.1/sdk/consumption/Azure.ResourceManager.Consumption/)
GitHub [1.1.0-beta.3](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Consumption_1.1.0-beta.3/sdk/consumption/Azure.ResourceManager.Consumption/) | | Resource Management - Container Apps | NuGet [1.5.0](https://www.nuget.org/packages/Azure.ResourceManager.AppContainers/1.5.0) | [docs](/dotnet/api/overview/azure/ResourceManager.AppContainers-readme) | GitHub [1.5.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.AppContainers_1.5.0/sdk/containerapps/Azure.ResourceManager.AppContainers/) | | Resource Management - Container Instances | NuGet [1.3.0](https://www.nuget.org/packages/Azure.ResourceManager.ContainerInstance/1.3.0) | [docs](/dotnet/api/overview/azure/ResourceManager.ContainerInstance-readme) | GitHub [1.3.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ContainerInstance_1.3.0/sdk/containerinstance/Azure.ResourceManager.ContainerInstance/) | @@ -412,7 +412,7 @@ | HTTP ASPNETCore Analyzers | NuGet [1.0.4](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.Analyzers/1.0.4) | | | | IoT Operations MQTT | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Iot.Operations.Mqtt/1.0.0) | | | | IoT Operations Protocol | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Iot.Operations.Protocol/1.0.0) | | | -| IoT Operations Services | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Iot.Operations.Services/1.0.0)
NuGet [1.1.0-rc](https://www.nuget.org/packages/Azure.Iot.Operations.Services/1.1.0-rc) | | | +| IoT Operations Services | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Iot.Operations.Services/1.0.0)
NuGet [1.2.0-rc2](https://www.nuget.org/packages/Azure.Iot.Operations.Services/1.2.0-rc2) | | | | Item Templates NetCore | NuGet [4.0.5337](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.ItemTemplates.NetCore/4.0.5337) | | | | Item Templates NetFx | NuGet [4.0.5337](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.ItemTemplates.NetFx/4.0.5337) | | | | Microsoft.Azure.DataFactoryTestingFramework.Expressions | NuGet [0.2.7](https://www.nuget.org/packages/Microsoft.Azure.DataFactoryTestingFramework.Expressions/0.2.7) | | | @@ -424,7 +424,7 @@ | Speech Extension ONNX Runtime | NuGet [1.47.0](https://www.nuget.org/packages/Microsoft.CognitiveServices.Speech.Extension.ONNX.Runtime/1.47.0) | | | | Speech Extension Telemetry | NuGet [1.47.0](https://www.nuget.org/packages/Microsoft.CognitiveServices.Speech.Extension.Telemetry/1.47.0) | | | | System Net Client Model | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/System.Net.ClientModel/1.0.0-beta.1) | | | -| Unknown Display Name | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Iot.Operations.Connector/1.0.0) | | | +| Unknown Display Name | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Iot.Operations.Connector/1.0.0)
NuGet [1.1.0-rc](https://www.nuget.org/packages/Azure.Iot.Operations.Connector/1.1.0-rc) | | | | Unknown Display Name | NuGet [0.1.0](https://www.nuget.org/packages/Azure.Iot.Operations.Templates/0.1.0) | | | | Unknown Display Name | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Mcp/1.0.0)
NuGet [2.0.0-beta.10](https://www.nuget.org/packages/Azure.Mcp/2.0.0-beta.10) | | | | Unknown Display Name | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Mcp.linux-arm64/1.0.0)
NuGet [2.0.0-beta.10](https://www.nuget.org/packages/Azure.Mcp.linux-arm64/2.0.0-beta.10) | | | @@ -438,7 +438,7 @@ | Unknown Display Name | NuGet [0.2.804](https://www.nuget.org/packages/Microsoft.Azure.Mcp.AzTypes.Internal.Compact/0.2.804) | | | | Unknown Display Name | NuGet [1.1.2-preview](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.AzureCosmosDb.Mongo/1.1.2-preview) | | | | Unknown Display Name | NuGet [1.47.0](https://www.nuget.org/packages/Microsoft.CognitiveServices.Speech.Extension.MAS/1.47.0) | | | -| Unknown Display Name | NuGet [1.1.0](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres/1.1.0) | | | +| Unknown Display Name | NuGet [1.2.0](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres/1.2.0) | | | | Unknown Display Name | NuGet [0.0.0-beta.5](https://www.nuget.org/packages/Microsoft.Fabric.Mcp/0.0.0-beta.5) | | | | Unknown Display Name | NuGet [0.0.0-beta.5](https://www.nuget.org/packages/Microsoft.Fabric.Mcp.linux-arm64/0.0.0-beta.5) | | | | Unknown Display Name | NuGet [0.0.0-beta.5](https://www.nuget.org/packages/Microsoft.Fabric.Mcp.linux-x64/0.0.0-beta.5) | | | @@ -551,8 +551,8 @@ | Functions extension for Azure SQL and SQL Server | NuGet [3.1.527](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Sql/3.1.527) | | | | Functions extension for Cosmos DB | NuGet [4.14.0](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.CosmosDB/4.14.0) | | GitHub [4.14.0](https://github.com/Azure/azure-webjobs-sdk-extensions/tree/cosmos-v3.0.7/src/WebJobs.Extensions.CosmosDB) | | Functions extension for DocumentDB | NuGet [1.3.0](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.DocumentDB/1.3.0) | | GitHub [1.3.0](https://github.com/Azure/azure-webjobs-sdk-extensions) | -| Functions extension for Durable Task Framework | NuGet [3.9.0](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.DurableTask/3.9.0) | [docs](/dotnet/api/overview/azure/functions) | GitHub [3.9.0](https://github.com/Azure/azure-functions-durable-extension/tree/v2.2.2/src/WebJobs.Extensions.DurableTask) | -| Functions extension for Durable Task Framework - isolated worker | NuGet [1.13.0](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.DurableTask/1.13.0) | | | +| Functions extension for Durable Task Framework | NuGet [3.9.1](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.DurableTask/3.9.1) | [docs](/dotnet/api/overview/azure/functions) | GitHub [3.9.1](https://github.com/Azure/azure-functions-durable-extension/tree/v2.2.2/src/WebJobs.Extensions.DurableTask) | +| Functions extension for Durable Task Framework - isolated worker | NuGet [1.13.1](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.DurableTask/1.13.1) | | | | Functions extension for HTTP | NuGet [3.3.0](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Http/3.3.0) | | GitHub [3.3.0](https://github.com/Azure/azure-webjobs-sdk-extensions/tree/v3.0.2/src/WebJobs.Extensions.Http) | | Functions extension for IoT Edge | NuGet [1.0.7](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.EdgeHub/1.0.7) | | GitHub [1.0.7](https://github.com/Azure/iotedge/tree/1.0.7/edge-hub) | | Functions extension for Kafka | NuGet [4.2.0](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Kafka/4.2.0) | | GitHub [4.2.0](https://github.com/Azure/azure-functions-kafka-extension/tree/3.0.0/src/Microsoft.Azure.WebJobs.Extensions.Kafka) | diff --git a/docs/azure/includes/dotnet-new.md b/docs/azure/includes/dotnet-new.md index 194de7debc511..301806228beb1 100644 --- a/docs/azure/includes/dotnet-new.md +++ b/docs/azure/includes/dotnet-new.md @@ -86,7 +86,7 @@ | OpenAI Assistants | NuGet [1.0.0-beta.4](https://www.nuget.org/packages/Azure.AI.OpenAI.Assistants/1.0.0-beta.4) | [docs](/dotnet/api/overview/azure/AI.OpenAI.Assistants-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.4](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.OpenAI.Assistants_1.0.0-beta.4/sdk/openai/Azure.AI.OpenAI.Assistants/) | | OpenAI Inference | NuGet [2.1.0](https://www.nuget.org/packages/Azure.AI.OpenAI/2.1.0)
NuGet [2.8.0-beta.1](https://www.nuget.org/packages/Azure.AI.OpenAI/2.8.0-beta.1) | [docs](/dotnet/api/overview/azure/AI.OpenAI-readme) | GitHub [2.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.OpenAI_2.1.0/sdk/openai/Azure.AI.OpenAI/)
GitHub [2.8.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.OpenAI_2.8.0-beta.1/sdk/openai/Azure.AI.OpenAI/) | | OpenTelemetry AspNetCore | NuGet [1.4.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.AspNetCore/1.4.0) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.AspNetCore-readme) | GitHub [1.4.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.AspNetCore_1.4.0/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/) | -| OpenTelemetry Exporter | NuGet [1.5.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.5.0)
NuGet [1.6.0-beta.1](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.6.0-beta.1) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.Exporter-readme) | GitHub [1.5.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.5.0/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/)
GitHub [1.6.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.6.0-beta.1/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/) | +| OpenTelemetry Exporter | NuGet [1.5.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.5.0)
NuGet [1.6.0-beta.2](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.6.0-beta.2) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.Exporter-readme) | GitHub [1.5.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.5.0/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/)
GitHub [1.6.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.6.0-beta.2/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/) | | OpenTelemetry LiveMetrics | NuGet [1.0.0-beta.3](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.LiveMetrics/1.0.0-beta.3) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.LiveMetrics-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.3](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.LiveMetrics_1.0.0-beta.3/sdk/monitor/Azure.Monitor.OpenTelemetry.LiveMetrics/) | | Personalizer | NuGet [2.0.0-beta.2](https://www.nuget.org/packages/Azure.AI.Personalizer/2.0.0-beta.2) | [docs](/dotnet/api/overview/azure/AI.Personalizer-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [2.0.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.AI.Personalizer_2.0.0-beta.2/sdk/personalizer/Azure.AI.Personalizer/) | | Playwright | NuGet [1.0.0](https://www.nuget.org/packages/Azure.Developer.Playwright/1.0.0) | [docs](/dotnet/api/overview/azure/Developer.Playwright-readme) | GitHub [1.0.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright_1.0.0/sdk/loadtestservice/Azure.Developer.Playwright/) | @@ -226,7 +226,7 @@ | Resource Management - Confidential Ledger | NuGet [1.0.1](https://www.nuget.org/packages/Azure.ResourceManager.ConfidentialLedger/1.0.1)
NuGet [1.1.0-beta.6](https://www.nuget.org/packages/Azure.ResourceManager.ConfidentialLedger/1.1.0-beta.6) | [docs](/dotnet/api/overview/azure/ResourceManager.ConfidentialLedger-readme) | GitHub [1.0.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConfidentialLedger_1.0.1/sdk/confidentialledger/Azure.ResourceManager.ConfidentialLedger/)
GitHub [1.1.0-beta.6](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConfidentialLedger_1.1.0-beta.6/sdk/confidentialledger/Azure.ResourceManager.ConfidentialLedger/) | | Resource Management - Confluent | NuGet [1.2.1](https://www.nuget.org/packages/Azure.ResourceManager.Confluent/1.2.1) | [docs](/dotnet/api/overview/azure/ResourceManager.Confluent-readme) | GitHub [1.2.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Confluent_1.2.1/sdk/confluent/Azure.ResourceManager.Confluent/) | | Resource Management - Connected VMware vSphere | NuGet [1.1.1](https://www.nuget.org/packages/Azure.ResourceManager.ConnectedVMwarevSphere/1.1.1) | [docs](/dotnet/api/overview/azure/ResourceManager.ConnectedVMwarevSphere-readme) | GitHub [1.1.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConnectedVMwarevSphere_1.1.1/sdk/connectedvmwarevsphere/Azure.ResourceManager.ConnectedVMwarevSphere/) | -| Resource Management - Connectedcache | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.ResourceManager.ConnectedCache/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/ResourceManager.ConnectedCache-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConnectedCache_1.0.0-beta.1/sdk/connectedcache/Azure.ResourceManager.ConnectedCache/) | +| Resource Management - Connectedcache | NuGet [1.0.0-beta.2](https://www.nuget.org/packages/Azure.ResourceManager.ConnectedCache/1.0.0-beta.2) | [docs](/dotnet/api/overview/azure/ResourceManager.ConnectedCache-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.2](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ConnectedCache_1.0.0-beta.2/sdk/connectedcache/Azure.ResourceManager.ConnectedCache/) | | Resource Management - Consumption | NuGet [1.0.1](https://www.nuget.org/packages/Azure.ResourceManager.Consumption/1.0.1)
NuGet [1.1.0-beta.3](https://www.nuget.org/packages/Azure.ResourceManager.Consumption/1.1.0-beta.3) | [docs](/dotnet/api/overview/azure/ResourceManager.Consumption-readme) | GitHub [1.0.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Consumption_1.0.1/sdk/consumption/Azure.ResourceManager.Consumption/)
GitHub [1.1.0-beta.3](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.Consumption_1.1.0-beta.3/sdk/consumption/Azure.ResourceManager.Consumption/) | | Resource Management - Container Apps | NuGet [1.5.0](https://www.nuget.org/packages/Azure.ResourceManager.AppContainers/1.5.0) | [docs](/dotnet/api/overview/azure/ResourceManager.AppContainers-readme) | GitHub [1.5.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.AppContainers_1.5.0/sdk/containerapps/Azure.ResourceManager.AppContainers/) | | Resource Management - Container Instances | NuGet [1.3.0](https://www.nuget.org/packages/Azure.ResourceManager.ContainerInstance/1.3.0) | [docs](/dotnet/api/overview/azure/ResourceManager.ContainerInstance-readme) | GitHub [1.3.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.ResourceManager.ContainerInstance_1.3.0/sdk/containerinstance/Azure.ResourceManager.ContainerInstance/) | diff --git a/docs/azure/install-azure-cli.md b/docs/azure/install-azure-cli.md index 62ca138e962e2..757e59a2b7cf6 100644 --- a/docs/azure/install-azure-cli.md +++ b/docs/azure/install-azure-cli.md @@ -4,8 +4,6 @@ description: Azure developers will need the Azure CLI installed, so this article ms.topic: concept-article ms.custom: devx-track-dotnet, engagement-fy23, devx-track-azurecli ms.date: 8/15/2024 -author: alexwolfmsft -ms.author: alexwolf --- # Install the Azure CLI diff --git a/docs/azure/migration/appcat/visual-studio-copilot.md b/docs/azure/migration/appcat/visual-studio-copilot.md index 38a879f53866d..01f731f5cdc67 100644 --- a/docs/azure/migration/appcat/visual-studio-copilot.md +++ b/docs/azure/migration/appcat/visual-studio-copilot.md @@ -3,9 +3,9 @@ title: Use GitHub Copilot for Visual Studio with the Azure Migrate application a description: Learn how to use GitHub Copilot with the Azure Migrate application and code assessment tool for .NET when evaluating apps for Azure migrations. ms.topic: concept-article ms.date: 10/09/2024 -author: alexwolfmsft -ms.author: alexwolf ms.custom: sfi-image-nochange +ms.collection: ce-skilling-ai-copilot +ms.update-cycle: 180-days --- # Use Copilot Conversational Assessment with the Azure Migrate application and code assessment tool diff --git a/docs/azure/migration/appmod/copilot-cli-support.md b/docs/azure/migration/appmod/copilot-cli-support.md index 1cf53b19f461d..277d38538164b 100644 --- a/docs/azure/migration/appmod/copilot-cli-support.md +++ b/docs/azure/migration/appmod/copilot-cli-support.md @@ -4,8 +4,6 @@ description: Overview of migrating .NET applications to Azure using GitHub Copil ms.topic: concept-article ms.custom: devx-track-dotnet ms.date: 11/11/2025 -author: alexwolfmsft -ms.author: alexwolf ms.reviewer: jessiehuang --- diff --git a/docs/azure/migration/appmod/predefined-tasks.md b/docs/azure/migration/appmod/predefined-tasks.md index 765d18d2ac311..e5a77e0165137 100644 --- a/docs/azure/migration/appmod/predefined-tasks.md +++ b/docs/azure/migration/appmod/predefined-tasks.md @@ -4,8 +4,6 @@ description: Learn about the predefined tasks that are available for GitHub Copi ms.topic: concept-article ms.custom: devx-track-dotnet ms.date: 9/17/2025 -author: alexwolfmsft -ms.author: alexwolf --- # Predefined tasks for GitHub Copilot app modernization for .NET @@ -27,35 +25,35 @@ Predefined tasks capture industry best practices for using Azure services. Curre App Modernization for .NET currently supports the following predefined tasks: - **Migrate to Managed Identity based Database on Azure, including Azure SQL DB, Azure SQL MI and Azure PostgreSQL** - + Modernize your data layer by migrating from on-premises or legacy databases (such as DB2, Oracle DB, or SQL Server) to Azure SQL DB, Azure SQL Managed Instance or Azure PostgreSQL, using secure managed identity authentication. - **Migrate to Azure File Storage** - + Move file I/O operations from the local file system to Azure File Storage for scalable, cloud-based file management. - **Migrate to Azure Blob Storage** - + Replace on-premises or cross-cloud object storage, or local file system file I/O, with Azure Blob Storage for unstructured data. - **Migrate to Microsoft Entra ID** - + Transition authentication and authorization from Windows Active Directory to Microsoft Entra ID (formerly Azure AD) for modern identity management. - **Migrate to secured credentials with Managed Identity and Azure Key Vault** - + Replace plaintext credentials in configuration or code with secure, managed identities and Azure Key Vault for secrets management. - **Migrate to Azure Service Bus** - + Move from legacy or third-party message queues (such as MSMQ or RabbitMQ) or Amazon SQS (AWS Simple Queue Service) to Azure Service Bus for reliable, cloud-based messaging. - **Migrate to Azure Communication Service email** - + Replace direct SMTP email sending with Azure Communication Service for scalable, secure email delivery. - **Migrate to Confluent Cloud/Azure Event Hub for Apache Kafka** - + Transition from local or on-premises Kafka to managed event streaming with Confluent Cloud or Azure Event Hubs. - **Migrate to OpenTelemetry on Azure** diff --git a/docs/azure/migration/appmod/quickstart.md b/docs/azure/migration/appmod/quickstart.md index 7536f2fac137a..112ed94de3c9f 100644 --- a/docs/azure/migration/appmod/quickstart.md +++ b/docs/azure/migration/appmod/quickstart.md @@ -5,8 +5,6 @@ description: Learn how to assess and migrate a .NET project by using GitHub Copi ms.topic: quickstart ms.custom: devx-track-dotnet ms.date: 09/22/2025 -author: alexwolfmsft -ms.author: alexwolf #customer intent: As a .NET developer, I want to assess my project's migration readiness so that I can identify potential challenges and plan the modernization process effectively. --- diff --git a/docs/azure/migration/appmod/sample.md b/docs/azure/migration/appmod/sample.md index 9dd635c5c2167..f65d217644d08 100644 --- a/docs/azure/migration/appmod/sample.md +++ b/docs/azure/migration/appmod/sample.md @@ -4,8 +4,6 @@ description: Learn about the sample project for GitHub Copilot app modernization ms.topic: concept-article ms.custom: devx-track-dotnet ms.date: 7/15/2025 -author: alexwolfmsft -ms.author: alexwolf --- # Contoso University migration sample diff --git a/docs/azure/sdk/snippets/aspnetcore-guidance/MinApiSample/MinApiSample.csproj b/docs/azure/sdk/snippets/aspnetcore-guidance/MinApiSample/MinApiSample.csproj index d5c51d157f672..16aea8f2a6914 100644 --- a/docs/azure/sdk/snippets/aspnetcore-guidance/MinApiSample/MinApiSample.csproj +++ b/docs/azure/sdk/snippets/aspnetcore-guidance/MinApiSample/MinApiSample.csproj @@ -7,10 +7,10 @@ - + - + diff --git a/docs/azure/sdk/snippets/authentication/Directory.Packages.props b/docs/azure/sdk/snippets/authentication/Directory.Packages.props index a13ebe98b1c95..e3f399e14f725 100644 --- a/docs/azure/sdk/snippets/authentication/Directory.Packages.props +++ b/docs/azure/sdk/snippets/authentication/Directory.Packages.props @@ -11,7 +11,7 @@ - + diff --git a/docs/core/compatibility/10.md b/docs/core/compatibility/10.md index 7ce4047ef2761..b9ea1e493395f 100644 --- a/docs/core/compatibility/10.md +++ b/docs/core/compatibility/10.md @@ -109,6 +109,7 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af | Title | Type of change | |-------|-------------------| | [HTTP/3 support disabled by default with PublishTrimmed](networking/10.0/http3-disabled-with-publishtrimmed.md) | Source incompatible | +| [MailAddress enforces validation for consecutive dots](networking/10.0/mailaddress-consecutive-dots.md) | Behavioral change | | [Streaming HTTP responses enabled by default in browser HTTP clients](networking/10.0/default-http-streaming.md) | Behavioral change | | [`Uri` length limits removed](networking/10.0/uri-length-limits-removed.md) | Behavioral change | diff --git a/docs/core/compatibility/11.md b/docs/core/compatibility/11.md index 8ded84052a641..8572f1eb62f0f 100644 --- a/docs/core/compatibility/11.md +++ b/docs/core/compatibility/11.md @@ -23,6 +23,12 @@ If you're migrating an app to .NET 11, the breaking changes listed here might af | [MemoryStream maximum capacity updated and exception behavior changed](core-libraries/11/memorystream-max-capacity.md) | Behavioral change | | [TAR-reading APIs verify header checksums when reading](core-libraries/11/tar-checksum-validation.md) | Behavioral change | +## Cryptography + +| Title | Type of change | +|------------------------------------------------------------------|-------------------| +| [DSA removed from macOS](cryptography/11/dsa-removed-macos.md) | Behavioral change | + ## Globalization | Title | Type of change | diff --git a/docs/core/compatibility/9.0.md b/docs/core/compatibility/9.0.md index ab432adf72955..f70431ccce592 100644 --- a/docs/core/compatibility/9.0.md +++ b/docs/core/compatibility/9.0.md @@ -68,6 +68,7 @@ If you're migrating an app to .NET 9, the breaking changes listed here might aff | Title | Type of change | Introduced version | |-----------------------------------------------------------------------------------------------------|---------------------|--------------------| | [Deprecated desktop Windows/macOS/Linux MonoVM runtime packages](deployment/9.0/monovm-packages.md) | Source incompatible | Preview 7 | +| [Environment variables take precedence in app runtime configuration settings](deployment/9.0/envvar-precedence.md) | Behavioral change | GA | ## Entity Framework Core diff --git a/docs/core/compatibility/core-libraries/10.0/filepatternmatch-stem-nonnullable.md b/docs/core/compatibility/core-libraries/10.0/filepatternmatch-stem-nonnullable.md index 5206615e82e83..c74307593041d 100644 --- a/docs/core/compatibility/core-libraries/10.0/filepatternmatch-stem-nonnullable.md +++ b/docs/core/compatibility/core-libraries/10.0/filepatternmatch-stem-nonnullable.md @@ -48,7 +48,7 @@ The previous nullability annotations were inaccurate, and a `null` value for the ## Recommended action -If a possibly null value was passed in for the `stem` argument, review usage and update the call site to ensure `stem` can't be paTssed in as `null`. +If a possibly null value was passed in for the `stem` argument, review usage and update the call site to ensure `stem` can't be passed in as `null`. If you applied nullability warning suppressions when consuming the `FilePatternMatch.Stem` property, you can remove those suppressions. diff --git a/docs/core/compatibility/core-libraries/8.0/system-io-packaging-case-insensitive-uri.md b/docs/core/compatibility/core-libraries/8.0/system-io-packaging-case-insensitive-uri.md index c9059b2ad9dd4..56be480543417 100644 --- a/docs/core/compatibility/core-libraries/8.0/system-io-packaging-case-insensitive-uri.md +++ b/docs/core/compatibility/core-libraries/8.0/system-io-packaging-case-insensitive-uri.md @@ -3,7 +3,6 @@ title: "Breaking change: Package part URIs are now compared case-insensitively i description: "Learn about the breaking change in .NET 8 where System.IO.Packaging now compares package part URIs case-insensitively to align with the OPC specification." ms.date: 09/29/2024 ai-usage: ai-generated -ms.custom: https://github.com/dotnet/runtime/issues/112783 --- # Package part URIs are now compared case-insensitively in System.IO.Packaging diff --git a/docs/core/compatibility/cryptography/11/dsa-removed-macos.md b/docs/core/compatibility/cryptography/11/dsa-removed-macos.md new file mode 100644 index 0000000000000..f8fd012423397 --- /dev/null +++ b/docs/core/compatibility/cryptography/11/dsa-removed-macos.md @@ -0,0 +1,47 @@ +--- +title: "Breaking change: DSA removed from macOS" +description: "Learn about the breaking change in .NET 11 where the Digital Signature Algorithm (DSA) is no longer supported on macOS." +ms.date: 01/07/2026 +ai-usage: ai-assisted +ms.custom: https://github.com/dotnet/docs/issues/48201 +--- + +# DSA removed from macOS + +Starting in .NET 11, the Digital Signature Algorithm (DSA) is no longer supported on macOS. This removal only impacts "finite field" DSA. Elliptic Curve DSA (EC-DSA) isn't affected. Attempts to use , , or other APIs that interact with DSA throw a on macOS. + +## Version introduced + +.NET 11 Preview 1 + +## Previous behavior + +Previously, the DSA algorithm and its supporting types, , , and X.509 certificates with DSA keys functioned on macOS. + +## New behavior + +DSA is no longer functional on macOS. Attempts to use , , or other APIs that interact with DSA throw a . + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +.NET on macOS relies on the operating system to provide an implementation of DSA. Apple did this through a now obsolete library called SecurityTransforms, with no replacement. The implementation that Apple did offer was also limited in functionality. It only supported DSA-1024 with SHA-1, which is considered weak. Further, it never supported generating DSA keys. + +iOS, tvOS, and MacCatalyst never supported DSA. + +## Recommended action + +Migrate away from the DSA algorithm and use a modern cryptographic digital signature algorithm such as EC-DSA (Elliptic Curve DSA). + +## Affected APIs + +* +* [DSACryptoServiceProvider constructors](xref:System.Security.Cryptography.DSACryptoServiceProvider.%23ctor*) +* +* +* + +Additionally, any APIs that interact with DSA keys are affected. diff --git a/docs/core/compatibility/deployment/8.0/opensuse-sles-openssl3-dependency.md b/docs/core/compatibility/deployment/8.0/opensuse-sles-openssl3-dependency.md index ef074b41b0cf4..90713bb5f2967 100644 --- a/docs/core/compatibility/deployment/8.0/opensuse-sles-openssl3-dependency.md +++ b/docs/core/compatibility/deployment/8.0/opensuse-sles-openssl3-dependency.md @@ -2,7 +2,6 @@ title: "Breaking change: .NET packages for openSUSE and SLES depend on OpenSSL 3.x" description: "Learn about the breaking change in .NET 8 where .NET packages for openSUSE and SLES distributions now depend on OpenSSL 3.x instead of OpenSSL 1.x." ms.date: 01/05/2026 -ms.custom: https://github.com/dotnet/runtime/issues/122653 ai-usage: ai-assisted --- # .NET packages for openSUSE and SLES depend on OpenSSL 3.x diff --git a/docs/core/compatibility/deployment/9.0/envvar-precedence.md b/docs/core/compatibility/deployment/9.0/envvar-precedence.md new file mode 100644 index 0000000000000..d65ec359b86ce --- /dev/null +++ b/docs/core/compatibility/deployment/9.0/envvar-precedence.md @@ -0,0 +1,57 @@ +--- +title: "Breaking change: Environment variables take precedence in app runtime configuration settings" +description: "Learn about the breaking change in .NET 9 where environment variables take precedence over runtimeconfig.json settings for configuring the runtime." +ms.date: 01/09/2026 +ai-usage: ai-assisted +--- +# Environment variables take precedence in app runtime configuration settings + +Starting in .NET 9, the priority of how app runtime configuration is resolved has changed. If both an environment variable and a corresponding setting in the application's `runtimeconfig.json` (or project file) are provided, the environment variable takes precedence over the configuration file. + +## Version introduced + +.NET 9 + +## Previous behavior + +Previously, when both an environment variable and the corresponding setting in the application's `runtimeconfig.json` were set, the `runtimeconfig.json` took precedence. + +For example, consider an application with the following `runtimeconfig.json` file: + +```json +{ + "runtimeOptions": { + "configProperties": { + "System.GC.Server": true + } + } +} +``` + +If the environment variable `DOTNET_gcServer` was set to `0` (false), the application would still use server garbage collection because the `runtimeconfig.json` setting took precedence. The environment variable was effectively ignored. + +## New behavior + +Starting in .NET 9, when both an environment variable and the corresponding setting in the application's `runtimeconfig.json` are set, the environment variable takes precedence. + +Using the same example as in the [Previous behavior](#previous-behavior) section, if the environment variable `DOTNET_gcServer` is set to `0` (false), the application now uses workstation garbage collection instead of server garbage collection, even though `runtimeconfig.json` specifies `System.GC.Server` as `true`. The environment variable overrides the configuration file setting. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +The new behavior is more consistent with how configuration tends to work in .NET and elsewhere, with environment variables taking precedence. + +## Recommended action + +If your app runs in an environment with runtime configuration environment variables set to values different than what's desired, either unset the environment variable or set it to the desired configuration value. + +## Affected APIs + +None. + +## See also + +- [.NET runtime configuration settings](../../../runtime-config/index.md) diff --git a/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md b/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md index 835a5fcb1ba81..b59f61276b67e 100644 --- a/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md +++ b/docs/core/compatibility/extensions/10.0/getkeyedservice-anykey.md @@ -21,7 +21,7 @@ Calling `GetKeyedServices()` with `KeyedService.AnyKey` returned all registratio ## New behavior -Starting in .NET 10, calling `GetKeyedService()` with `KeyedService.AnyKey` throws an . This ensures that `AnyKey` can't be used to resolve a single service, as it's intended to represent a special case rather than a specific key. +Starting in .NET 10, calling `GetKeyedService()` with `KeyedService.AnyKey` throws an . This ensures that `AnyKey` can't be used to resolve a single service, as it's [intended to represent a special case](../../../extensions/dependency-injection.md#keyedserviceanykey-property) rather than a specific key. ```csharp var service = serviceProvider.GetKeyedService(typeof(IMyService), KeyedService.AnyKey); @@ -45,13 +45,16 @@ The previous behavior of `GetKeyedService()` and `GetKeyedServices()` with `Keye ## Recommended action -If you use `GetKeyedService()` or `GetKeyedServices()` with `KeyedService.AnyKey`, review your code and update it to use specific keys instead of `AnyKey`. +If you use `GetKeyedService()` or `GetKeyedServices()` with `KeyedService.AnyKey`, review your code and update it to use specific keys instead of `AnyKey`: -For `GetKeyedService(KeyedService.AnyKey)`, replace calls to `GetKeyedService()` with `KeyedService.AnyKey` with specific keys or alternative logic to handle service resolution. - -For `GetKeyedServices(KeyedService.AnyKey)`, replace calls to `GetKeyedServices()` with `KeyedService.AnyKey` with calls that use specific keys, or update your logic to enumerate only the services you intend to retrieve. +- Replace `GetKeyedService(KeyedService.AnyKey)` calls with specific keys or alternative logic to handle service resolution. +- Replace `GetKeyedServices(KeyedService.AnyKey)` calls with specific keys, or update your logic to enumerate only the services you intend to retrieve. ## Affected APIs - - + +## See also + +- [Use KeyedService.AnyKey for fallbacks](../../../extensions/dependency-injection.md#keyedserviceanykey-property) diff --git a/docs/core/compatibility/networking/10.0/mailaddress-consecutive-dots.md b/docs/core/compatibility/networking/10.0/mailaddress-consecutive-dots.md new file mode 100644 index 0000000000000..1e3eedd856a6e --- /dev/null +++ b/docs/core/compatibility/networking/10.0/mailaddress-consecutive-dots.md @@ -0,0 +1,83 @@ +--- +title: "Breaking change - MailAddress enforces validation for consecutive dots" +description: "Learn about the breaking change in .NET 10 where MailAddress enforces stricter validation of email addresses with consecutive dots." +ms.date: 01/12/2026 +ai-usage: ai-assisted +ms.custom: https://github.com/dotnet/docs/issues/51018 +--- + +# MailAddress enforces validation for consecutive dots + +Starting in .NET 10, the class enforces stricter validation of email addresses. Email addresses with consecutive dots in the local part (for example, `test..address@example.com`) or domain part (for example, `address@test..example.com`) are now considered invalid. This change aligns the behavior of `MailAddress` with the email address format specified in [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322.html) and [RFC 2822](https://www.rfc-editor.org/rfc/rfc2822.html). + +## Version introduced + +.NET 10 Preview 1 + +## Previous behavior + +Previously, the class allowed email addresses with consecutive dots in the local or domain parts, even though such addresses are invalid according to the email address specification. + +For example, the following code executed without throwing an exception: + +```csharp +using System.Net.Mail; + +var email = new MailAddress("test..address@example.com"); +Console.WriteLine(email.Address); // Output: test..address@example.com +``` + +## New behavior + +Starting in .NET 10, the class enforces stricter validation and throws a when it parses an email address with consecutive dots in the local or domain parts. + +For example, the following code now throws a : + +```csharp +using System.Net.Mail; + +var email = new MailAddress("test..address@example.com"); // Throws FormatException +``` + +The exception message indicates that the email address is invalid. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +This change ensures compliance with the email address format specified in [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322.html) and [RFC 2822](https://www.rfc-editor.org/rfc/rfc2822.html). According to these standards, email addresses with consecutive dots in the local or domain parts are invalid. The previous behavior of allowing such addresses was incorrect and could lead to unexpected issues in applications relying on for email validation. + +## Recommended action + +If your application relies on the class to parse email addresses, review your code to ensure that it doesn't pass email addresses with consecutive dots in the local or domain parts. If such addresses are encountered, update your application to handle the that's now thrown. + +For example, you can use a `try-catch` block to handle invalid email addresses: + +```csharp +using System; +using System.Net.Mail; + +try +{ + var email = new MailAddress("test..address@example.com"); +} +catch (FormatException ex) +{ + Console.WriteLine($"Invalid email address: {ex.Message}"); +} +``` + +Alternatively, you can validate email addresses using a regular expression before passing them to the constructor. + +## Affected APIs + +- constructor +- constructor +- constructor + +## See also + +- [Original pull request](https://github.com/dotnet/runtime/pull/109690) +- [Related issue](https://github.com/dotnet/runtime/issues/109590) diff --git a/docs/core/compatibility/sdk/10.0/dnx-ps1-removed.md b/docs/core/compatibility/sdk/10.0/dnx-ps1-removed.md index 0fc1188ebb0b8..79237e9f5c28e 100644 --- a/docs/core/compatibility/sdk/10.0/dnx-ps1-removed.md +++ b/docs/core/compatibility/sdk/10.0/dnx-ps1-removed.md @@ -3,7 +3,6 @@ title: "Breaking change - dnx.ps1 file is no longer included in .NET SDK" description: "Learn about the breaking change in .NET 10 where the dnx.ps1 script is no longer included in Windows versions of the .NET SDK." ms.date: 10/13/2025 ai-usage: ai-assisted -ms.custom: https://github.com/dotnet/docs/issues/497988 --- # dnx.ps1 file is no longer included in .NET SDK diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 92a4e59be37e3..052fc53dbaf89 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -18,6 +18,10 @@ items: href: core-libraries/11/memorystream-max-capacity.md - name: TAR-reading APIs verify header checksums when reading href: core-libraries/11/tar-checksum-validation.md + - name: Cryptography + items: + - name: DSA removed from macOS + href: cryptography/11/dsa-removed-macos.md - name: Globalization items: - name: Japanese Calendar minimum supported date corrected @@ -142,6 +146,8 @@ items: items: - name: HTTP/3 support disabled by default with PublishTrimmed href: networking/10.0/http3-disabled-with-publishtrimmed.md + - name: MailAddress enforces validation for consecutive dots + href: networking/10.0/mailaddress-consecutive-dots.md - name: Streaming HTTP responses enabled by default in browser HTTP clients href: networking/10.0/default-http-streaming.md - name: "'Uri' length limits removed" @@ -306,6 +312,8 @@ items: items: - name: Deprecated desktop Windows/macOS/Linux MonoVM runtime packages href: deployment/9.0/monovm-packages.md + - name: Environment variables take precedence in app runtime configuration settings + href: deployment/9.0/envvar-precedence.md - name: Entity Framework Core href: /ef/core/what-is-new/ef-core-9.0/breaking-changes?toc=/dotnet/core/compatibility/toc.json&bc=/dotnet/breadcrumb/toc.json - name: Interop diff --git a/docs/core/compatibility/unsupported-apis.md b/docs/core/compatibility/unsupported-apis.md index 864b69782a092..8425608369512 100644 --- a/docs/core/compatibility/unsupported-apis.md +++ b/docs/core/compatibility/unsupported-apis.md @@ -2,7 +2,7 @@ title: Unsupported APIs on .NET Core and .NET 5+ titleSuffix: "" description: Learn which .NET APIs always throw an exception on .NET Core and .NET 5 and later versions. -ms.date: 11/07/2025 +ms.date: 01/08/2026 --- # APIs that always throw exceptions on .NET (Core) @@ -265,6 +265,11 @@ This article organizes the affected APIs by namespace. | | Linux and macOS | | | Linux and macOS | | | Linux and macOS | +| \* | macOS | +| \* | macOS | +| \* | macOS | +| \* | macOS | +| \* | macOS | | | macOS | | | All | | | All | @@ -297,6 +302,8 @@ This article organizes the affected APIs by namespace. | | All | | | All | +\* .NET 11 and later versions. + ## System.Security.Cryptography.Pkcs | Member | Platforms that throw | diff --git a/docs/core/dependency-loading/default-probing.md b/docs/core/dependency-loading/default-probing.md index e3022eb63482e..864da921b52d7 100644 --- a/docs/core/dependency-loading/default-probing.md +++ b/docs/core/dependency-loading/default-probing.md @@ -64,6 +64,8 @@ When probing to locate a managed assembly, the in `TRUSTED_PLATFORM_ASSEMBLIES` (after removing file extensions). - Assembly files in `APP_PATHS` with common file extensions. +When loading in the default , assemblies found in `TRUSTED_PLATFORM_ASSEMBLIES` or `APP_PATHS` take precedence over a specified path or raw assembly object. For example, if you call or on the default and an assembly with a matching name exists in `TRUSTED_PLATFORM_ASSEMBLIES` or `APP_PATHS`, the runtime loads the assembly from those locations instead of from the specified stream or path. + ## Satellite (resource) assembly probing To find a satellite assembly for a specific culture, construct a set of file paths. diff --git a/docs/core/dependency-loading/loading-managed.md b/docs/core/dependency-loading/loading-managed.md index 2d083a2f07ac4..908394ad0b4f9 100644 --- a/docs/core/dependency-loading/loading-managed.md +++ b/docs/core/dependency-loading/loading-managed.md @@ -51,6 +51,7 @@ The following algorithm describes how the runtime loads a managed assembly. 3. For the other types of loads, the `active` loads the assembly in the following priority order: - Check its `cache-by-name`. + - If the `active` is , run the [default probing logic for managed assemblies](default-probing.md#managed-assembly-default-probing). - Load from the specified path or raw assembly object. If an assembly is newly loaded, a reference is added to the `active` instance's `cache-by-name`. 4. In either case, if an assembly is newly loaded, then the event is raised. diff --git a/docs/core/diagnostics/collect-dumps-crash.md b/docs/core/diagnostics/collect-dumps-crash.md index 272572942dc3f..49dcca8067b26 100644 --- a/docs/core/diagnostics/collect-dumps-crash.md +++ b/docs/core/diagnostics/collect-dumps-crash.md @@ -16,6 +16,7 @@ The following table shows the environment variables you can configure for collec |`DOTNET_DbgMiniDumpType`|Type of dump to be collected. For more information, see [Types of mini dumps](#types-of-mini-dumps).|2 (`Heap`)| |`DOTNET_DbgMiniDumpName`|Path to a file to write the dump to. Ensure that the user under which the dotnet process is running has write permissions to the specified directory.|`/tmp/coredump.`| |`DOTNET_CreateDumpDiagnostics`|If set to 1, enables diagnostic logging of dump process.|0| +|`DOTNET_DbgCreateDumpToolPath`|(.NET 11+ NativeAOT only)
Path to the directory where the createdump tool is located. The runtime will look for the createdump binary in this directory. This variable is useful in scenarios where createdump isn't shipped with the runtime and you need to "bring your own" dump generation tool. This environment variable is only supported in NativeAOT applications and ignored otherwise.| | |`DOTNET_EnableCrashReport`|(not supported on Windows.)
If set to 1, the runtime generates a JSON-formatted crash report that includes information about the threads and stack frames of the crashing application. The crash report name is the dump path or name with *.crashreport.json* appended.| | |`DOTNET_CreateDumpVerboseDiagnostics`|If set to 1, enables verbose diagnostic logging of the dump process.|0| |`DOTNET_CreateDumpLogToFile`|The path of the file to which the diagnostic messages should be written. | If unset, the diagnostic messages are written to the console of the crashing application. | diff --git a/docs/core/diagnostics/snippets/Metrics/metric-instr.csproj b/docs/core/diagnostics/snippets/Metrics/metric-instr.csproj index 8a12dc96e3d6b..88ff7b7658dda 100644 --- a/docs/core/diagnostics/snippets/Metrics/metric-instr.csproj +++ b/docs/core/diagnostics/snippets/Metrics/metric-instr.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/diagnostics/snippets/MetricsGen/MetricsGen.csproj b/docs/core/diagnostics/snippets/MetricsGen/MetricsGen.csproj index c303f40bcf53e..321ab93a47b4a 100644 --- a/docs/core/diagnostics/snippets/MetricsGen/MetricsGen.csproj +++ b/docs/core/diagnostics/snippets/MetricsGen/MetricsGen.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/core/diagnostics/snippets/exception-summary/exception-summary.csproj b/docs/core/diagnostics/snippets/exception-summary/exception-summary.csproj index f985cdab77e5c..861b06cc7a7b7 100644 --- a/docs/core/diagnostics/snippets/exception-summary/exception-summary.csproj +++ b/docs/core/diagnostics/snippets/exception-summary/exception-summary.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/diagnostics/snippets/health-checks/health-checks.csproj b/docs/core/diagnostics/snippets/health-checks/health-checks.csproj index b8ec4d31f6c1c..529c3dd667a6a 100644 --- a/docs/core/diagnostics/snippets/health-checks/health-checks.csproj +++ b/docs/core/diagnostics/snippets/health-checks/health-checks.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/diagnostics/snippets/lifetime-health-checks/lifetime-health-checks.csproj b/docs/core/diagnostics/snippets/lifetime-health-checks/lifetime-health-checks.csproj index 86c3c81f7e961..1fd24c7bfd860 100644 --- a/docs/core/diagnostics/snippets/lifetime-health-checks/lifetime-health-checks.csproj +++ b/docs/core/diagnostics/snippets/lifetime-health-checks/lifetime-health-checks.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj b/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj index 3f8fc328bd77c..cc40b02bd5e54 100644 --- a/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj +++ b/docs/core/diagnostics/snippets/resource-monitoring/resource-monitoring.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/docs/core/enrichment/snippets/enrichment/Enrichment.csproj b/docs/core/enrichment/snippets/enrichment/Enrichment.csproj index 6c9a981ddff37..f8ea1c801eecc 100644 --- a/docs/core/enrichment/snippets/enrichment/Enrichment.csproj +++ b/docs/core/enrichment/snippets/enrichment/Enrichment.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/docs/core/extensions/dependency-injection.md b/docs/core/extensions/dependency-injection.md index 7039777a5ce0b..a0e0cc0f9b5cb 100644 --- a/docs/core/extensions/dependency-injection.md +++ b/docs/core/extensions/dependency-injection.md @@ -1,6 +1,6 @@ --- title: Dependency injection -description: Learn how to use dependency injection within your .NET apps. Discover how to registration services, define service lifetimes, and express dependencies in C#. +description: Learn how to use dependency injection within your .NET apps. Discover how to define service lifetimes and express dependencies in C#. ms.date: 10/21/2025 ms.topic: overview ai-usage: ai-assisted @@ -8,21 +8,13 @@ ai-usage: ai-assisted # .NET dependency injection -.NET supports the dependency injection (DI) software design pattern, which is a technique for achieving [Inversion of Control (IoC)](../../architecture/modern-web-apps-azure/architectural-principles.md#dependency-inversion) between classes and their dependencies. Dependency injection in .NET is a built-in part of the framework, along with configuration, logging, and the options pattern. +.NET supports the *dependency injection* (DI) software design pattern, which is a technique for achieving [Inversion of Control (IoC)](../../architecture/modern-web-apps-azure/architectural-principles.md#dependency-inversion) between classes and their dependencies. Dependency injection in .NET is a built-in part of the framework, along with configuration, logging, and the options pattern. -A *dependency* is an object that another object depends on. Examine the following `MessageWriter` class with a `Write` method that other classes depend on: +A *dependency* is an object that another object depends on. The following `MessageWriter` class has a `Write` method that other classes might depend on: -```csharp -public class MessageWriter -{ - public void Write(string message) - { - Console.WriteLine($"MessageWriter.Write(message: \"{message}\")"); - } -} -``` +:::code language="csharp" source="snippets/overview/Program.cs" id="SnippetMW"::: -A class can create an instance of the `MessageWriter` class to use its `Write` method. In the following example, the `MessageWriter` class is a dependency of the `Worker` class: +A class can create an instance of the `MessageWriter` class to use its `Write` method. In the following example, the `MessageWriter` class is a *dependency* of the `Worker` class: ```csharp public class Worker : BackgroundService @@ -40,91 +32,59 @@ public class Worker : BackgroundService } ``` -The class creates and directly depends on the `MessageWriter` class. Hard-coded dependencies, such as in the previous example, are problematic and should be avoided for the following reasons: +In this case, the `Worker` class creates and directly depends on the `MessageWriter` class. Hard-coded dependencies like this are problematic and should be avoided for the following reasons: - To replace `MessageWriter` with a different implementation, you must modify the `Worker` class. - If `MessageWriter` has dependencies, the `Worker` class must also configure them. In a large project with multiple classes depending on `MessageWriter`, the configuration code becomes scattered across the app. - This implementation is difficult to unit test. The app should use a mock or stub `MessageWriter` class, which isn't possible with this approach. -Dependency injection addresses the following problems through: - -- The use of an interface or base class to abstract the dependency implementation. -- Registration of the dependency in a service container. .NET provides a built-in service container, . Services are typically registered at the app's start-up and appended to an . Once all services are added, use to create the service container. -- *Injection* of the service into the constructor of the class where it's used. The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed. +## The concept -As an example, the `IMessageWriter` interface defines the `Write` method: +Dependency injection addresses hard-coded dependency problems through: -:::code language="csharp" source="snippets/configuration/dependency-injection/IMessageWriter.cs"::: +- The use of an interface or base class to abstract the dependency implementation. +- Registration of the dependency in a *service container*. -This interface is implemented by a concrete type, `MessageWriter`: + .NET provides a built-in service container, . Services are typically registered at the app's start-up and appended to an . Once all services are added, use to create the service container. -:::code language="csharp" source="snippets/configuration/dependency-injection/MessageWriter.cs"::: +- Injection of the service into the constructor of the class where it's used. -The sample code registers the `IMessageWriter` service with the concrete type `MessageWriter`. The method registers the service with a singleton lifetime, the lifetime of the app. [Service lifetimes](#service-lifetimes) are described later in this article. + The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed. -:::code language="csharp" source="snippets/configuration/dependency-injection/Program.cs" highlight="5-8"::: +> [!TIP] +> In dependency injection terminology, a *service* is typically an object that provides a service to other objects, such as the `IMessageWriter` service. The service isn't related to a web service, although it might use a web service. -In the preceding code, the sample app: +As an example, assume the `IMessageWriter` interface defines the `Write` method. This interface is implemented by a concrete type, `MessageWriter`, shown previously. The following sample code registers the `IMessageWriter` service with the concrete type `MessageWriter`. The method registers the service with a [*singleton* lifetime](#singleton), which means it isn't disposed until the app shuts down. -- Creates a host app builder instance. -- Configures the services by registering: +:::code language="csharp" source="snippets/overview/Program.cs" highlight="3-6"::: - - The `Worker` as a hosted service. For more information, see [Worker Services in .NET](workers.md). - - The `IMessageWriter` interface as a singleton service with a corresponding implementation of the `MessageWriter` class. +In the preceding code example, the highlighted lines: -- Builds the host and runs it. +- Create a host app builder instance. +- Configure the services by registering the `Worker` as a [hosted service](workers.md) and the `IMessageWriter` interface as a singleton service with a corresponding implementation of the `MessageWriter` class. +- Build the host and run it. The host contains the dependency injection service provider. It also contains all the other relevant services required to automatically instantiate the `Worker` and provide the corresponding `IMessageWriter` implementation as an argument. -:::code language="csharp" source="snippets/configuration/dependency-injection/Worker.cs"::: +By using the DI pattern, the worker service doesn't use the concrete type `MessageWriter`, only the `IMessageWriter` interface that it implements. This design makes it easy to change the implementation that the worker service uses without modifying the worker service. The worker service also doesn't *create an instance* of `MessageWriter`. The DI container creates the instance. -By using the DI pattern, the worker service: +Now, imagine you want to switch out `MessageWriter` with a type that uses the [framework-provided logging service](#framework-provided-services). Create a class `LoggingMessageWriter` that depends on by requesting it in the constructor. -- Doesn't use the concrete type `MessageWriter`, only the `IMessageWriter` interface that it implements. This makes it easy to change the implementation that the worker service uses without modifying the worker service. -- Doesn't create an instance of `MessageWriter`. The DI container creates the instance. +:::code language="csharp" source="snippets/overview/LoggingMessageWriter.cs"::: -The implementation of the `IMessageWriter` interface can be improved using the built-in logging API: - -:::code language="csharp" source="snippets/configuration/dependency-injection/LoggingMessageWriter.cs"::: - -The updated `AddSingleton` method registers the new `IMessageWriter` implementation: +To switch from `MessageWriter` to `LoggingMessageWriter`, simply update the call to `AddSingleton` to register this new `IMessageWriter` implementation: ```csharp builder.Services.AddSingleton(); ``` -The (`builder`) type is part of the `Microsoft.Extensions.Hosting` NuGet package. +> [!TIP] +> The container resolves `ILogger` by taking advantage of [(generic) open types](/dotnet/csharp/language-reference/language-specification/types#843-open-and-closed-types), which eliminates the need to register every [(generic) constructed type](/dotnet/csharp/language-reference/language-specification/types#84-constructed-types). -`LoggingMessageWriter` depends on , which it requests in the constructor. `ILogger` is a [framework-provided service](#framework-provided-services). +## Chaining It's not unusual to use dependency injection in a chained fashion. Each requested dependency in turn requests its own dependencies. The container resolves the dependencies in the graph and returns the fully resolved service. The collective set of dependencies that must be resolved is typically called a *dependency tree*, *dependency graph*, or *object graph*. -The container resolves `ILogger` by taking advantage of [(generic) open types](/dotnet/csharp/language-reference/language-specification/types#843-open-and-closed-types), eliminating the need to register every [(generic) constructed type](/dotnet/csharp/language-reference/language-specification/types#84-constructed-types). - -With dependency injection terminology, a service: - -- Is typically an object that provides a service to other objects, such as the `IMessageWriter` service. -- Isn't related to a web service, although the service might use a web service. - -The framework provides a robust logging system. The `IMessageWriter` implementations shown in the preceding examples demonstrate basic DI, not logging. Most apps shouldn't need to write loggers. The following code demonstrates using the default logging, which only requires the `Worker` to be registered as a hosted service : - -```csharp -public sealed class Worker(ILogger logger) : BackgroundService -{ - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - while (!stoppingToken.IsCancellationRequested) - { - logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); - - await Task.Delay(1_000, stoppingToken); - } - } -} -``` - -Using the preceding code, there's no need to update _Program.cs_, because the framework provides logging. - ## Multiple constructor discovery rules When a type defines more than one constructor, the service provider has logic for determining which constructor to use. The constructor with the most parameters where the types are DI-resolvable is selected. Consider the following C# example service: @@ -196,7 +156,7 @@ public class ExampleService ## Register groups of services with extension methods -Microsoft Extensions uses a convention for registering a group of related services. The convention is to use a single `Add{GROUP_NAME}` extension method to register all of the services required by a framework feature. For example, the extension method registers all of the services required for using options. +.NET uses a convention for registering a group of related services. The convention is to use a single `Add{GROUP_NAME}` extension method to register all of the services required by a framework feature. For example, the extension method registers all of the services required for using options. ## Framework-provided services @@ -213,17 +173,17 @@ After creating a builder from any of these APIs, the `IServiceCollection` has se The following table lists a small sample of these framework-registered services: -| Service Type | Lifetime | -|--|--| +| Service type | Lifetime | +|------------------------------------------------------------------------------------|-----------| | | Singleton | -| | Singleton | -| | Singleton | -| | Singleton | +| | Singleton | +| | Singleton | +| | Singleton | | | Singleton | -| | Transient | -| | Singleton | -| | Singleton | -| | Singleton | +| | Transient | +| | Singleton | +| | Singleton | +| | Singleton | ## Service lifetimes @@ -281,8 +241,8 @@ In apps that process requests, singleton services are disposed when the object
disposal | Multiple
implementations | Pass args | -|--|:-:|:-:|:-:| -| `Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()`

Example:

`services.AddSingleton();` | Yes | Yes | No | +|--------|:-------------------------------:|:---------------------------:|:---------:| +| `Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()`

Example:

`services.AddSingleton();` | Yes | Yes | No | | `Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION})`

Examples:

`services.AddSingleton(sp => new MyDep());`
`services.AddSingleton(sp => new MyDep(99));` | Yes | Yes | Yes | | `Add{LIFETIME}<{IMPLEMENTATION}>()`

Example:

`services.AddSingleton();` | Yes | No | No | | `AddSingleton<{SERVICE}>(new {IMPLEMENTATION})`

Examples:

`services.AddSingleton(new MyDep());`
`services.AddSingleton(new MyDep(99));` | No | Yes | Yes | @@ -380,12 +340,7 @@ The built-in `Add{LIFETIME}` methods use the same approach. For example, see the ### Constructor injection behavior -Services can be resolved using: - -- -- : - - Creates objects that aren't registered in the container. - - Used with some framework features. +Services can be resolved using or . `ActivatorUtilities` creates objects that aren't registered in the container and is used with some framework features. Constructors can accept arguments that aren't provided by dependency injection, but the arguments must assign default values. @@ -406,7 +361,7 @@ Scoped services are disposed by the container that created them. If a scoped ser ## Scope scenarios -The is always registered as a singleton, but the can vary based on the lifetime of the containing class. For example, if you resolve services from a scope, and any of those services take an , it is a scoped instance. +The is always registered as a singleton, but the can vary based on the lifetime of the containing class. For example, if you resolve services from a scope, and any of those services take an , it's a scoped instance. To achieve scoping services within implementations of , such as the , *don't* inject the service dependencies via constructor injection. Instead, inject , create a scope, then resolve dependencies from the scope to use the appropriate service lifetime. @@ -423,7 +378,7 @@ From the sample source code, you can see how implementations of property provides a special key for working with keyed services. You can register a service using `KeyedService.AnyKey` as a fallback that matches any key. This is useful when you want to provide a default implementation for any key that doesn't have an explicit registration. + +:::code language="csharp" source="snippets/di/anykey/csharp/AnyKeyExamples/Program.cs" id="FallbackRegistration"::: + +In the preceding example: + +- Requesting `ICache` with key `"premium"` returns the `PremiumCache` instance. +- Requesting `ICache` with any other key (like `"basic"` or `"standard"`) creates a new `DefaultCache` using the `AnyKey` fallback. + +> [!IMPORTANT] +> Starting in .NET 10, calling `GetKeyedService()` with `KeyedService.AnyKey` throws an because `AnyKey` is intended as a registration fallback, not as a query key. For more information, see [Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey](../compatibility/extensions/10.0/getkeyedservice-anykey.md). + ## See also -- [Understand dependency injection basics in .NET](dependency-injection-basics.md) -- [Use dependency injection in .NET](dependency-injection-usage.md) +- [Quickstart: Dependency injection basics](dependency-injection-basics.md) +- [Tutorial: Use dependency injection in .NET](dependency-injection-usage.md) - [Dependency injection guidelines](dependency-injection-guidelines.md) - [Dependency injection in ASP.NET Core](/aspnet/core/fundamentals/dependency-injection) - [NDC Conference Patterns for DI app development](https://www.youtube.com/watch?v=x-C-CNBVTaY) - [Explicit dependencies principle](../../architecture/modern-web-apps-azure/architectural-principles.md#explicit-dependencies) - [Inversion of control containers and the dependency injection pattern (Martin Fowler)](https://www.martinfowler.com/articles/injection.html) -- DI bugs should be created in the [github.com/dotnet/extensions](https://github.com/dotnet/extensions/issues) repo diff --git a/docs/core/extensions/globalization-icu.md b/docs/core/extensions/globalization-icu.md index fd5c152854233..c90341bdf32d5 100644 --- a/docs/core/extensions/globalization-icu.md +++ b/docs/core/extensions/globalization-icu.md @@ -180,7 +180,7 @@ Using ICU instead of NLS might result in behavioral differences with some global - By setting the environment variable `DOTNET_SYSTEM_GLOBALIZATION_USENLS` to the value `true` or `1`. > [!NOTE] -> A value set in the project or in the `runtimeconfig.json` file takes precedence over the environment variable. +> In .NET 9 and later versions, an environment variable setting takes precedence. In previous versions, a value set in the project or in the `runtimeconfig.json` file takes precedence over the environment variable. For more information, see [Runtime config settings](../../core/runtime-config/globalization.md#nls). diff --git a/docs/core/extensions/options.md b/docs/core/extensions/options.md index bf0b600f1fa99..a4e22a4713d13 100644 --- a/docs/core/extensions/options.md +++ b/docs/core/extensions/options.md @@ -16,7 +16,7 @@ Options also provide a mechanism to validate configuration data. For more inform ## Bind hierarchical configuration -The preferred way to read related configuration values is using the options pattern. The options pattern is possible through the interface, where the generic type parameter `TOptions` is constrained to a `class`. The `IOptions` can later be provided through dependency injection. For more information, see [Dependency injection in .NET](dependency-injection.md). +The preferred way to read related configuration values is using the options pattern. The options pattern is possible through the interface, where the generic type parameter `TOptions` is constrained to a `class`. The `IOptions` can later be provided through dependency injection. For more information, see [Dependency injection in .NET](dependency-injection.md). For example, to read the highlighted configuration values from an _appsettings.json_ file: @@ -80,20 +80,20 @@ In the preceding code, changes to the JSON configuration file after the app has ## Options interfaces -: +: - Does ***not*** support: - Reading of configuration data after the app has started. - [Named options](#named-options-support-using-iconfigurenamedoptions) - Is registered as a [Singleton](dependency-injection.md#singleton) and can be injected into any [service lifetime](dependency-injection.md#service-lifetimes). -: +: - Is useful in scenarios where options should be recomputed on every injection resolution, in [scoped or transient lifetimes](dependency-injection.md#service-lifetimes). For more information, see [Use IOptionsSnapshot to read updated data](#use-ioptionssnapshot-to-read-updated-data). - Is registered as [Scoped](dependency-injection.md#scoped) and therefore can't be injected into a Singleton service. - Supports [named options](#named-options-support-using-iconfigurenamedoptions). -: +: - Is used to retrieve options and manage options notifications for `TOptions` instances. - Is registered as a [Singleton](dependency-injection.md#singleton) and can be injected into any [service lifetime](dependency-injection.md#service-lifetimes). @@ -101,32 +101,32 @@ In the preceding code, changes to the JSON configuration file after the app has - Change notifications - [Named options](#named-options-support-using-iconfigurenamedoptions) - [Reloadable configuration](#use-ioptionssnapshot-to-read-updated-data) - - Selective options invalidation () + - Selective options invalidation () - is responsible for creating new options instances. It has a single method. The default implementation takes all registered and and runs all the configurations first, followed by the post-configuration. It distinguishes between and and only calls the appropriate interface. + is responsible for creating new options instances. It has a single method. The default implementation takes all registered and and runs all the configurations first, followed by the post-configuration. It distinguishes between and and only calls the appropriate interface. - is used by to cache `TOptions` instances. The invalidates options instances in the monitor so that the value is recomputed (). Values can be manually introduced with . The method is used when all named instances should be recreated on demand. + is used by to cache `TOptions` instances. The invalidates options instances in the monitor so that the value is recomputed (). Values can be manually introduced with . The method is used when all named instances should be recreated on demand. - is used to fetch the that tracks changes to the underlying `TOptions` instance. For more information on change-token primitives, see [Change notifications](primitives.md). + is used to fetch the that tracks changes to the underlying `TOptions` instance. For more information on change-token primitives, see [Change notifications](primitives.md). ### Options interfaces benefits -Using a generic wrapper type gives you the ability to decouple the lifetime of the option from the dependency injection (DI) container. The interface provides a layer of abstraction, including generic constraints, on your options type. This provides the following benefits: +Using a generic wrapper type gives you the ability to decouple the lifetime of the option from the dependency injection (DI) container. The interface provides a layer of abstraction, including generic constraints, on your options type. This provides the following benefits: -- The evaluation of the `T` configuration instance is deferred to the accessing of , rather than when it is injected. This is important because you can consume the `T` option from various places and choose the lifetime semantics without changing anything about `T`. +- The evaluation of the `T` configuration instance is deferred to the accessing of , rather than when it is injected. This is important because you can consume the `T` option from various places and choose the lifetime semantics without changing anything about `T`. - When registering options of type `T`, you don't need to explicitly register the `T` type. This is a convenience when you're [authoring a library](options-library-authors.md) with simple defaults, and you don't want to force the caller to register options into the DI container with a specific lifetime. - From the perspective of the API, it allows for constraints on the type `T` (in this case, `T` is constrained to a reference type). ## Use IOptionsSnapshot to read updated data -When you use , options are computed once per request when accessed and are cached for the lifetime of the request. Changes to the configuration are read after the app starts when using configuration providers that support reading updated configuration values. +When you use , options are computed once per request when accessed and are cached for the lifetime of the request. Changes to the configuration are read after the app starts when using configuration providers that support reading updated configuration values. The difference between `IOptionsMonitor` and `IOptionsSnapshot` is that: - `IOptionsMonitor` is a [singleton service](dependency-injection.md#singleton) that retrieves current option values at any time, which is especially useful in singleton dependencies. - `IOptionsSnapshot` is a [scoped service](dependency-injection.md#scoped) and provides a snapshot of the options at the time the `IOptionsSnapshot` object is constructed. Options snapshots are designed for use with transient and scoped dependencies. -The following code uses . +The following code uses . :::code language="csharp" source="snippets/configuration/console-json/ScopedService.cs"::: @@ -160,14 +160,14 @@ builder.Services nameof(TransientFaultHandlingOptions))); ``` -The following example uses : +The following example uses : :::code language="csharp" source="snippets/configuration/console-json/MonitorService.cs"::: In the preceding code, changes to the JSON configuration file after the app has started are read. > [!TIP] -> Some file systems, such as Docker containers and network shares, may not reliably send change notifications. When using the interface in these environments, set the `DOTNET_USE_POLLING_FILE_WATCHER` environment variable to `1` or `true` to poll the file system for changes. The interval at which changes are polled is every four seconds and isn't configurable. +> Some file systems, such as Docker containers and network shares, may not reliably send change notifications. When using the interface in these environments, set the `DOTNET_USE_POLLING_FILE_WATCHER` environment variable to `1` or `true` to poll the file system for changes. The interval at which changes are polled is every four seconds and isn't configurable. > > For more information on Docker containers, see [Containerize a .NET app](../docker/build-container.md). @@ -241,11 +241,11 @@ public sealed class Service } ``` -All options are named instances. instances are treated as targeting the `Options.DefaultName` instance, which is `string.Empty`. also implements . The default implementation of the has logic to use each appropriately. The `null` named option is used to target all of the named instances instead of a specific named instance. and use this convention. +All options are named instances. instances are treated as targeting the `Options.DefaultName` instance, which is `string.Empty`. also implements . The default implementation of the has logic to use each appropriately. The `null` named option is used to target all of the named instances instead of a specific named instance. and use this convention. ## OptionsBuilder API - is used to configure `TOptions` instances. `OptionsBuilder` streamlines creating named options as it's only a single parameter to the initial `AddOptions(string optionsName)` call instead of appearing in all of the subsequent calls. Options validation and the `ConfigureOptions` overloads that accept service dependencies are only available via `OptionsBuilder`. + is used to configure `TOptions` instances. `OptionsBuilder` streamlines creating named options as it's only a single parameter to the initial `AddOptions(string optionsName)` call instead of appearing in all of the subsequent calls. Options validation and the `ConfigureOptions` overloads that accept service dependencies are only available via `OptionsBuilder`. `OptionsBuilder` is used in the [Options validation](#options-validation) section. @@ -253,7 +253,7 @@ All options are named instances. ](xref:Microsoft.Extensions.Options.OptionsBuilder%601). `OptionsBuilder` provides overloads of [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder%601.Configure%2A) that allow use of up to five services to configure options: +- Pass a configuration delegate to [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder`1.Configure%2A) on [OptionsBuilder\](xref:Microsoft.Extensions.Options.OptionsBuilder`1). `OptionsBuilder` provides overloads of [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder`1.Configure%2A) that allow use of up to five services to configure options: ```csharp builder.Services @@ -263,9 +263,9 @@ When you're configuring options, you can use [dependency injection](dependency-i options.Property = DoSomethingWith(es, ss, ms)); ``` -- Create a type that implements or and register the type as a service. +- Create a type that implements or and register the type as a service. -It's recommended to pass a configuration delegate to [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder%601.Configure%2A), since creating a service is more complex. Creating a type is equivalent to what the framework does when calling [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder%601.Configure%2A). Calling [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder%601.Configure%2A) registers a transient generic , which has a constructor that accepts the generic service types specified. +It's recommended to pass a configuration delegate to [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder`1.Configure%2A), since creating a service is more complex. Creating a type is equivalent to what the framework does when calling [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder`1.Configure%2A). Calling [Configure](xref:Microsoft.Extensions.Options.OptionsBuilder`1.Configure%2A) registers a transient generic , which has a constructor that accepts the generic service types specified. ## Options validation @@ -294,7 +294,7 @@ In the preceding `SettingsOptions` class, the `ConfigurationSectionName` propert The following code: -- Calls to get an [OptionsBuilder\](xref:Microsoft.Extensions.Options.OptionsBuilder%601) that binds to the `SettingsOptions` class. +- Calls to get an [OptionsBuilder\](xref:Microsoft.Extensions.Options.OptionsBuilder`1) that binds to the `SettingsOptions` class. - Calls to enable validation using `DataAnnotations`. ```csharp @@ -347,7 +347,7 @@ builder.Services .ValidateOnStart(); ``` -Starting with .NET 8, you can use an alternate API, , that enables validation on start for a specific options type: +To enable validation on start for a specific options type, use the API: ```csharp builder.Services @@ -367,7 +367,7 @@ builder.Services ### `IValidateOptions` for complex validation -The following class implements : +The following class implements : :::code language="csharp" source="snippets/configuration/console-json/ValidateSettingsOptions.cs"::: @@ -392,9 +392,32 @@ builder.Services.TryAddEnumerable( , ValidateSettingsOptions>()); ``` +### Recursive validation with `ValidateObjectMembers` and `ValidateEnumeratedItems` + +By default, `DataAnnotations` validation only validates the properties of the options class itself. It doesn't recursively validate nested objects or items in collections. To enable recursive validation, use the and attributes. + +- The attribute enables recursive validation of nested objects. +- The attribute enables recursive validation of enumerable objects. + +Consider the following nested options classes: + +:::code language="csharp" source="snippets/configuration/options-recursive-validation/DatabaseOptions.cs" id="DatabaseOptions"::: + +:::code language="csharp" source="snippets/configuration/options-recursive-validation/ServerOptions.cs" id="ServerOptions"::: + +:::code language="csharp" source="snippets/configuration/options-recursive-validation/ApplicationOptions.cs" id="ApplicationOptionsWithAttribute"::: + +In the preceding code, the `Database` property is a nested object of type `DatabaseOptions`. + +- Without the `[ValidateObjectMembers]` attribute applied to the `DatabaseOptions` property, the validation attributes on _its_ properties (like `[Required]` on `ConnectionString`) would not be evaluated. With `[ValidateObjectMembers]` applied, the validation also recurses into the `Database` property and validates its members according to their `DataAnnotations` attributes. +- Without the `[ValidateEnumeratedItems]` attribute applied to the `Servers` collection property, the validation attributes on individual `ServerOptions` items would not be evaluated. With the `[ValidateEnumeratedItems]` attribute applied, each `ServerOptions` item in the list is validated according to its `DataAnnotations` attributes. + +> [!TIP] +> Both `ValidateObjectMembersAttribute` and `ValidateEnumeratedItemsAttribute` work with the compile-time options validation source generator for improved performance. For more information, see [Compile-time options validation source generation](options-validation-generator.md). + ## Options post-configuration -Set post-configuration with . Post-configuration runs after all configuration occurs, and can be useful in scenarios when you need to override configuration: +Set post-configuration with . Post-configuration runs after all configuration occurs, and can be useful in scenarios when you need to override configuration: ```csharp builder.Services.PostConfigure(customOptions => @@ -403,7 +426,7 @@ builder.Services.PostConfigure(customOptions => }); ``` - is available to post-configure named options: + is available to post-configure named options: ```csharp builder.Services.PostConfigure("named_options_1", customOptions => diff --git a/docs/core/extensions/snippets/caching/memory-worker/memory-worker.csproj b/docs/core/extensions/snippets/caching/memory-worker/memory-worker.csproj index 3b22de22f720c..2e5cb42fe9bc8 100644 --- a/docs/core/extensions/snippets/caching/memory-worker/memory-worker.csproj +++ b/docs/core/extensions/snippets/caching/memory-worker/memory-worker.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj b/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj index 172bb598caa60..0655dc61f2da5 100644 --- a/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj +++ b/docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/configuration.sln b/docs/core/extensions/snippets/configuration/configuration.sln index 8f7374a168a11..9de9b6cf7419c 100644 --- a/docs/core/extensions/snippets/configuration/configuration.sln +++ b/docs/core/extensions/snippets/configuration/configuration.sln @@ -45,8 +45,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "console-xml", "console-xml\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "custom-provider", "custom-provider\custom-provider.csproj", "{B366FEA5-FB69-4CE2-87B9-2470FA3C69F1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dependency-injection", "dependency-injection\dependency-injection.csproj", "{E7F32B1F-46E6-4DAD-8929-F4C301202A70}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "di-anti-patterns", "di-anti-patterns\di-anti-patterns.csproj", "{BEF829E5-EED9-4B9D-8ECE-2DFC3C240946}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "options-action", "options-action\options-action.csproj", "{BBCE4882-E6C2-4017-B5F9-3AF4ED8CADF3}" diff --git a/docs/core/extensions/snippets/configuration/console-basic/console-basic.csproj b/docs/core/extensions/snippets/configuration/console-basic/console-basic.csproj index d4e9fd8085a15..9c569bdd2ee9e 100644 --- a/docs/core/extensions/snippets/configuration/console-basic/console-basic.csproj +++ b/docs/core/extensions/snippets/configuration/console-basic/console-basic.csproj @@ -14,8 +14,8 @@
- - + + diff --git a/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj b/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj index 582bf27201161..ff8f23e22c231 100644 --- a/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj +++ b/docs/core/extensions/snippets/configuration/console-binder-gen/console-binder-gen.csproj @@ -13,10 +13,10 @@ - - - - + + + + diff --git a/docs/core/extensions/snippets/configuration/console-custom-logging/console-custom-logging.csproj b/docs/core/extensions/snippets/configuration/console-custom-logging/console-custom-logging.csproj index f7bbc0ca306f7..f4cf436f57f62 100644 --- a/docs/core/extensions/snippets/configuration/console-custom-logging/console-custom-logging.csproj +++ b/docs/core/extensions/snippets/configuration/console-custom-logging/console-custom-logging.csproj @@ -19,9 +19,9 @@
- - - + + + diff --git a/docs/core/extensions/snippets/configuration/console-di-disposable/console-di-disposable.csproj b/docs/core/extensions/snippets/configuration/console-di-disposable/console-di-disposable.csproj index b26fed1e94150..16afd9138dcc5 100644 --- a/docs/core/extensions/snippets/configuration/console-di-disposable/console-di-disposable.csproj +++ b/docs/core/extensions/snippets/configuration/console-di-disposable/console-di-disposable.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-di-ienumerable/console-di-ienumerable.csproj b/docs/core/extensions/snippets/configuration/console-di-ienumerable/console-di-ienumerable.csproj index b88d4a0320071..d33fd19163992 100644 --- a/docs/core/extensions/snippets/configuration/console-di-ienumerable/console-di-ienumerable.csproj +++ b/docs/core/extensions/snippets/configuration/console-di-ienumerable/console-di-ienumerable.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-di/console-di.csproj b/docs/core/extensions/snippets/configuration/console-di/console-di.csproj index eaf169a28a0f3..e0876e4a1a0ee 100644 --- a/docs/core/extensions/snippets/configuration/console-di/console-di.csproj +++ b/docs/core/extensions/snippets/configuration/console-di/console-di.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-env/console-env.csproj b/docs/core/extensions/snippets/configuration/console-env/console-env.csproj index 5b34ee995f626..95471c7bf4a0b 100644 --- a/docs/core/extensions/snippets/configuration/console-env/console-env.csproj +++ b/docs/core/extensions/snippets/configuration/console-env/console-env.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-host/console-host.csproj b/docs/core/extensions/snippets/configuration/console-host/console-host.csproj index b8bbb5c773225..5b855b2280d2a 100644 --- a/docs/core/extensions/snippets/configuration/console-host/console-host.csproj +++ b/docs/core/extensions/snippets/configuration/console-host/console-host.csproj @@ -19,9 +19,9 @@
- - - + + + diff --git a/docs/core/extensions/snippets/configuration/console-indexer/console-indexer.csproj b/docs/core/extensions/snippets/configuration/console-indexer/console-indexer.csproj index d4e9fd8085a15..9c569bdd2ee9e 100644 --- a/docs/core/extensions/snippets/configuration/console-indexer/console-indexer.csproj +++ b/docs/core/extensions/snippets/configuration/console-indexer/console-indexer.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-ini/console-ini.csproj b/docs/core/extensions/snippets/configuration/console-ini/console-ini.csproj index 78ce0bea7e526..8d3e041a5f377 100644 --- a/docs/core/extensions/snippets/configuration/console-ini/console-ini.csproj +++ b/docs/core/extensions/snippets/configuration/console-ini/console-ini.csproj @@ -19,9 +19,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/configuration/console-json/console-json.csproj b/docs/core/extensions/snippets/configuration/console-json/console-json.csproj index c8b5b8cea5f25..5ed26b91a9be8 100644 --- a/docs/core/extensions/snippets/configuration/console-json/console-json.csproj +++ b/docs/core/extensions/snippets/configuration/console-json/console-json.csproj @@ -19,9 +19,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/configuration/console-memory/console-memory.csproj b/docs/core/extensions/snippets/configuration/console-memory/console-memory.csproj index 4f9d2e77b6205..f2124ae45b123 100644 --- a/docs/core/extensions/snippets/configuration/console-memory/console-memory.csproj +++ b/docs/core/extensions/snippets/configuration/console-memory/console-memory.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/console-raw/console-raw.csproj b/docs/core/extensions/snippets/configuration/console-raw/console-raw.csproj index b76a0de0bb5c2..1af2a463aa61a 100644 --- a/docs/core/extensions/snippets/configuration/console-raw/console-raw.csproj +++ b/docs/core/extensions/snippets/configuration/console-raw/console-raw.csproj @@ -14,9 +14,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj b/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj index 2f5923f73c943..732282b68ef4a 100644 --- a/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj +++ b/docs/core/extensions/snippets/configuration/console-validation-gen/console-validation-gen.csproj @@ -19,10 +19,10 @@ - - - - + + + + diff --git a/docs/core/extensions/snippets/configuration/console-xml/console-xml.csproj b/docs/core/extensions/snippets/configuration/console-xml/console-xml.csproj index aaa0f3b43676a..7774aec729f08 100644 --- a/docs/core/extensions/snippets/configuration/console-xml/console-xml.csproj +++ b/docs/core/extensions/snippets/configuration/console-xml/console-xml.csproj @@ -23,9 +23,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/configuration/console/console.csproj b/docs/core/extensions/snippets/configuration/console/console.csproj index 3784d45cb5780..a43038d661a35 100644 --- a/docs/core/extensions/snippets/configuration/console/console.csproj +++ b/docs/core/extensions/snippets/configuration/console/console.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj b/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj index 677d952954f18..ab7c42b4674c6 100644 --- a/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj +++ b/docs/core/extensions/snippets/configuration/custom-provider/custom-provider.csproj @@ -9,11 +9,11 @@ - - - - - + + + + + diff --git a/docs/core/extensions/snippets/configuration/dependency-injection/IMessageWriter.cs b/docs/core/extensions/snippets/configuration/dependency-injection/IMessageWriter.cs deleted file mode 100644 index dc85aeaf428dd..0000000000000 --- a/docs/core/extensions/snippets/configuration/dependency-injection/IMessageWriter.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace DependencyInjection.Example; - -public interface IMessageWriter -{ - void Write(string message); -} diff --git a/docs/core/extensions/snippets/configuration/dependency-injection/MessageWriter.cs b/docs/core/extensions/snippets/configuration/dependency-injection/MessageWriter.cs deleted file mode 100644 index 118702d2734a8..0000000000000 --- a/docs/core/extensions/snippets/configuration/dependency-injection/MessageWriter.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace DependencyInjection.Example; - -public class MessageWriter : IMessageWriter -{ - public void Write(string message) - { - Console.WriteLine($"MessageWriter.Write(message: \"{message}\")"); - } -} diff --git a/docs/core/extensions/snippets/configuration/dependency-injection/Program.cs b/docs/core/extensions/snippets/configuration/dependency-injection/Program.cs deleted file mode 100644 index ef79801a87fa5..0000000000000 --- a/docs/core/extensions/snippets/configuration/dependency-injection/Program.cs +++ /dev/null @@ -1,10 +0,0 @@ -using DependencyInjection.Example; - -HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); - -builder.Services.AddHostedService(); -builder.Services.AddSingleton(); - -using IHost host = builder.Build(); - -host.Run(); diff --git a/docs/core/extensions/snippets/configuration/dependency-injection/Worker.cs b/docs/core/extensions/snippets/configuration/dependency-injection/Worker.cs deleted file mode 100644 index c40efdf98efae..0000000000000 --- a/docs/core/extensions/snippets/configuration/dependency-injection/Worker.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace DependencyInjection.Example; - -public sealed class Worker(IMessageWriter messageWriter) : BackgroundService -{ - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - while (!stoppingToken.IsCancellationRequested) - { - messageWriter.Write($"Worker running at: {DateTimeOffset.Now}"); - await Task.Delay(1_000, stoppingToken); - } - } -} diff --git a/docs/core/extensions/snippets/configuration/di-anti-patterns/di-anti-patterns.csproj b/docs/core/extensions/snippets/configuration/di-anti-patterns/di-anti-patterns.csproj index ceff09400d881..cc1ce5c0b7f58 100644 --- a/docs/core/extensions/snippets/configuration/di-anti-patterns/di-anti-patterns.csproj +++ b/docs/core/extensions/snippets/configuration/di-anti-patterns/di-anti-patterns.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/options-action/options-action.csproj b/docs/core/extensions/snippets/configuration/options-action/options-action.csproj index 3563962d73912..bb1ac6ca202b0 100644 --- a/docs/core/extensions/snippets/configuration/options-action/options-action.csproj +++ b/docs/core/extensions/snippets/configuration/options-action/options-action.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/options-configparam/options-configparam.csproj b/docs/core/extensions/snippets/configuration/options-configparam/options-configparam.csproj index 2a7f7d282a40a..7c72a60ef2462 100644 --- a/docs/core/extensions/snippets/configuration/options-configparam/options-configparam.csproj +++ b/docs/core/extensions/snippets/configuration/options-configparam/options-configparam.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj b/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj index fd6fd49eb26df..9d5d424d0c50a 100644 --- a/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj +++ b/docs/core/extensions/snippets/configuration/options-noparams/options-noparams.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/options-object/options-object.csproj b/docs/core/extensions/snippets/configuration/options-object/options-object.csproj index 56ab8b49f9bd3..5a222ff2af9bd 100644 --- a/docs/core/extensions/snippets/configuration/options-object/options-object.csproj +++ b/docs/core/extensions/snippets/configuration/options-object/options-object.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/options-postconfig/options-postconfig.csproj b/docs/core/extensions/snippets/configuration/options-postconfig/options-postconfig.csproj index 31b0565590347..a598f6260ad3c 100644 --- a/docs/core/extensions/snippets/configuration/options-postconfig/options-postconfig.csproj +++ b/docs/core/extensions/snippets/configuration/options-postconfig/options-postconfig.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/ApplicationOptions.cs b/docs/core/extensions/snippets/configuration/options-recursive-validation/ApplicationOptions.cs new file mode 100644 index 0000000000000..a57b5dac19006 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/ApplicationOptions.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.Extensions.Options; + +namespace RecursiveValidation.Example; + +// +public sealed class ApplicationOptionsWithAttribute +{ + public const string ConfigurationSectionName = "ApplicationWithAttribute"; + + [Required] + public required string ApplicationName { get; set; } + + // Validation recurses into DatabaseOptions. + [ValidateObjectMembers] + public DatabaseOptions Database { get; set; } = new(); + + // Validation recurses into each ServerOptions in the list. + [ValidateEnumeratedItems] + public List Servers { get; set; } = []; +} +// diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/DatabaseOptions.cs b/docs/core/extensions/snippets/configuration/options-recursive-validation/DatabaseOptions.cs new file mode 100644 index 0000000000000..088dd46aa5c83 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/DatabaseOptions.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace RecursiveValidation.Example; + +// +public sealed class DatabaseOptions +{ + [Required] + [MinLength(1)] + public string ConnectionString { get; set; } = string.Empty; + + [Range(1, 100)] + public int MaxRetries { get; set; } = 3; + + [Range(1, 300)] + public int TimeoutSeconds { get; set; } = 30; +} +// diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/Program.cs b/docs/core/extensions/snippets/configuration/options-recursive-validation/Program.cs new file mode 100644 index 0000000000000..ef4aedd671a1d --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/Program.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using RecursiveValidation.Example; + +// +HostApplicationBuilder builderWith = Host.CreateApplicationBuilder(args); + +builderWith.Services + .AddOptions() + .Bind(builderWith.Configuration.GetSection( + ApplicationOptionsWithAttribute.ConfigurationSectionName)) + .ValidateDataAnnotations() + .ValidateOnStart(); + +IHost hostWith = builderWith.Build(); + +try +{ + var optionsWith = hostWith.Services + .GetRequiredService>().Value; + + Console.WriteLine("With [ValidateObjectMembers] and [ValidateEnumeratedItems]:"); + Console.WriteLine($" Application: {optionsWith.ApplicationName}"); + Console.WriteLine($" Database Connection: {optionsWith.Database.ConnectionString}"); + Console.WriteLine($" Servers Count: {optionsWith.Servers.Count}"); + Console.WriteLine(" Validation succeeded (nested objects were validated!)"); +} +catch (OptionsValidationException ex) +{ + Console.WriteLine("With attributes - Validation failed:"); + foreach (var failure in ex.Failures) + { + Console.WriteLine($" - {failure}"); + } +} +// diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/ServerOptions.cs b/docs/core/extensions/snippets/configuration/options-recursive-validation/ServerOptions.cs new file mode 100644 index 0000000000000..5ce660ffe5bca --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/ServerOptions.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace RecursiveValidation.Example; + +// +public sealed class ServerOptions +{ + [Required] + [RegularExpression(@"^[a-zA-Z0-9\-\.]+$")] + public string HostName { get; set; } = string.Empty; + + [Required] + [Range(1, 65535)] + public int Port { get; set; } +} +// diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/appsettings-invalid.json b/docs/core/extensions/snippets/configuration/options-recursive-validation/appsettings-invalid.json new file mode 100644 index 0000000000000..7380458e11a50 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/appsettings-invalid.json @@ -0,0 +1,30 @@ +{ + "ApplicationWithoutAttribute": { + "ApplicationName": "My App", + "Database": { + "ConnectionString": "", + "MaxRetries": 150, + "TimeoutSeconds": 500 + }, + "Servers": [ + { + "HostName": "invalid hostname with spaces", + "Port": 0 + } + ] + }, + "ApplicationWithAttribute": { + "ApplicationName": "My App", + "Database": { + "ConnectionString": "", + "MaxRetries": 150, + "TimeoutSeconds": 500 + }, + "Servers": [ + { + "HostName": "invalid hostname with spaces", + "Port": 0 + } + ] + } +} diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/appsettings.json b/docs/core/extensions/snippets/configuration/options-recursive-validation/appsettings.json new file mode 100644 index 0000000000000..86f6122d8d7a5 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/appsettings.json @@ -0,0 +1,38 @@ +{ + "ApplicationWithoutAttribute": { + "ApplicationName": "My App", + "Database": { + "ConnectionString": "Server=localhost;Database=mydb", + "MaxRetries": 5, + "TimeoutSeconds": 60 + }, + "Servers": [ + { + "HostName": "server1.example.com", + "Port": 8080 + }, + { + "HostName": "server2.example.com", + "Port": 8081 + } + ] + }, + "ApplicationWithAttribute": { + "ApplicationName": "My App", + "Database": { + "ConnectionString": "Server=localhost;Database=mydb", + "MaxRetries": 5, + "TimeoutSeconds": 60 + }, + "Servers": [ + { + "HostName": "server1.example.com", + "Port": 8080 + }, + { + "HostName": "server2.example.com", + "Port": 8081 + } + ] + } +} diff --git a/docs/core/extensions/snippets/configuration/options-recursive-validation/options-recursive-validation.csproj b/docs/core/extensions/snippets/configuration/options-recursive-validation/options-recursive-validation.csproj new file mode 100644 index 0000000000000..68102e08c3133 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/options-recursive-validation/options-recursive-validation.csproj @@ -0,0 +1,29 @@ + + + + Exe + net10.0 + enable + true + RecursiveValidation.Example + + + + + + + + + PreserveNewest + + + + + + + + + + + + diff --git a/docs/core/extensions/snippets/configuration/options-validation-onstart/options-validation-onstart.csproj b/docs/core/extensions/snippets/configuration/options-validation-onstart/options-validation-onstart.csproj index 8cfd41d3acc5f..ea4d451e095b7 100644 --- a/docs/core/extensions/snippets/configuration/options-validation-onstart/options-validation-onstart.csproj +++ b/docs/core/extensions/snippets/configuration/options-validation-onstart/options-validation-onstart.csproj @@ -19,9 +19,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/configuration/worker-scope/worker-scope.csproj b/docs/core/extensions/snippets/configuration/worker-scope/worker-scope.csproj index 24b803917f74a..051fb34bf115f 100644 --- a/docs/core/extensions/snippets/configuration/worker-scope/worker-scope.csproj +++ b/docs/core/extensions/snippets/configuration/worker-scope/worker-scope.csproj @@ -8,7 +8,7 @@ - - + + diff --git a/docs/core/extensions/snippets/configuration/worker-service/worker-service.csproj b/docs/core/extensions/snippets/configuration/worker-service/worker-service.csproj index 3d6b2d42a96cd..6d195335b9f8b 100644 --- a/docs/core/extensions/snippets/configuration/worker-service/worker-service.csproj +++ b/docs/core/extensions/snippets/configuration/worker-service/worker-service.csproj @@ -9,7 +9,7 @@ - - + + diff --git a/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/AnyKeyExamples.csproj b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/AnyKeyExamples.csproj new file mode 100644 index 0000000000000..4640e52ac1fa7 --- /dev/null +++ b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/AnyKeyExamples.csproj @@ -0,0 +1,14 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + diff --git a/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/DefaultCache.cs b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/DefaultCache.cs new file mode 100644 index 0000000000000..d7fcd05f6c29e --- /dev/null +++ b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/DefaultCache.cs @@ -0,0 +1,22 @@ +namespace AnyKeyExamples; + +// +public class DefaultCache : ICache +{ + private readonly string _cacheType; + private readonly Dictionary _data = new(); + + public DefaultCache(string cacheType) + { + _cacheType = cacheType; + } + + public string GetData(string key) => + _data.TryGetValue(key, out var value) ? value : $"No data in {_cacheType} cache"; + + public void SetData(string key, string value) => + _data[key] = value; + + public override string ToString() => $"{_cacheType} cache"; +} +// diff --git a/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/ICache.cs b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/ICache.cs new file mode 100644 index 0000000000000..dff43f68427b3 --- /dev/null +++ b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/ICache.cs @@ -0,0 +1,9 @@ +namespace AnyKeyExamples; + +// +public interface ICache +{ + string GetData(string key); + void SetData(string key, string value); +} +// diff --git a/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/PremiumCache.cs b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/PremiumCache.cs new file mode 100644 index 0000000000000..0753c9ede9c70 --- /dev/null +++ b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/PremiumCache.cs @@ -0,0 +1,16 @@ +namespace AnyKeyExamples; + +// +public class PremiumCache : ICache +{ + private readonly Dictionary _data = new(); + + public string GetData(string key) => + _data.TryGetValue(key, out var value) ? value : "No data in premium cache"; + + public void SetData(string key, string value) => + _data[key] = value; + + public override string ToString() => "Premium cache"; +} +// diff --git a/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/Program.cs b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/Program.cs new file mode 100644 index 0000000000000..c29141f0ccdf6 --- /dev/null +++ b/docs/core/extensions/snippets/di/anykey/csharp/AnyKeyExamples/Program.cs @@ -0,0 +1,33 @@ +using AnyKeyExamples; +using Microsoft.Extensions.DependencyInjection; +FallbackExample(); + +static void FallbackExample() +{ + // + var services = new ServiceCollection(); + + // Register a fallback cache for any key. + services.AddKeyedSingleton(KeyedService.AnyKey, (sp, key) => + { + // Create a cache instance based on the key. + return new DefaultCache(key?.ToString() ?? "unknown"); + }); + + // Register a specific cache for the "premium" key. + services.AddKeyedSingleton("premium", new PremiumCache()); + + var provider = services.BuildServiceProvider(); + + // Requesting with "premium" key returns PremiumCache. + var premiumCache = provider.GetKeyedService("premium"); + Console.WriteLine($"Premium key: {premiumCache}"); + + // Requesting with any other key uses the AnyKey fallback. + var basicCache = provider.GetKeyedService("basic"); + Console.WriteLine($"Basic key: {basicCache}"); + + var standardCache = provider.GetKeyedService("standard"); + Console.WriteLine($"Standard key: {standardCache}"); + // +} diff --git a/docs/core/extensions/snippets/fileglobbing/example/example.csproj b/docs/core/extensions/snippets/fileglobbing/example/example.csproj index d89bccd2f9396..17e279eea7d9a 100644 --- a/docs/core/extensions/snippets/fileglobbing/example/example.csproj +++ b/docs/core/extensions/snippets/fileglobbing/example/example.csproj @@ -59,8 +59,8 @@ - - + + diff --git a/docs/core/extensions/snippets/http/latency/latency.csproj b/docs/core/extensions/snippets/http/latency/latency.csproj index aabfe22d16dcb..c643620bbca20 100644 --- a/docs/core/extensions/snippets/http/latency/latency.csproj +++ b/docs/core/extensions/snippets/http/latency/latency.csproj @@ -18,7 +18,7 @@ - + diff --git a/docs/core/extensions/snippets/http/typed/typed.csproj b/docs/core/extensions/snippets/http/typed/typed.csproj index 3859126583c56..69c006ce797d7 100644 --- a/docs/core/extensions/snippets/http/typed/typed.csproj +++ b/docs/core/extensions/snippets/http/typed/typed.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/localization/example/example.csproj b/docs/core/extensions/snippets/localization/example/example.csproj index 352f30b2bfa02..b13978a1bf6a6 100644 --- a/docs/core/extensions/snippets/localization/example/example.csproj +++ b/docs/core/extensions/snippets/localization/example/example.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/logging/console-formatter-custom-with-config/console-formatter-custom-with-config.csproj b/docs/core/extensions/snippets/logging/console-formatter-custom-with-config/console-formatter-custom-with-config.csproj index bf513a3b96cdf..ce27838409777 100644 --- a/docs/core/extensions/snippets/logging/console-formatter-custom-with-config/console-formatter-custom-with-config.csproj +++ b/docs/core/extensions/snippets/logging/console-formatter-custom-with-config/console-formatter-custom-with-config.csproj @@ -19,7 +19,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/console-formatter-custom/console-formatter-custom.csproj b/docs/core/extensions/snippets/logging/console-formatter-custom/console-formatter-custom.csproj index 1819f4a8e2555..186042ddf9825 100644 --- a/docs/core/extensions/snippets/logging/console-formatter-custom/console-formatter-custom.csproj +++ b/docs/core/extensions/snippets/logging/console-formatter-custom/console-formatter-custom.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/console-formatter-json/console-formatter-json.csproj b/docs/core/extensions/snippets/logging/console-formatter-json/console-formatter-json.csproj index 1b070a4808dc9..79c29b9004448 100644 --- a/docs/core/extensions/snippets/logging/console-formatter-json/console-formatter-json.csproj +++ b/docs/core/extensions/snippets/logging/console-formatter-json/console-formatter-json.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/console-formatter-simple/console-formatter-simple.csproj b/docs/core/extensions/snippets/logging/console-formatter-simple/console-formatter-simple.csproj index cc54958ae8043..57dce425d654e 100644 --- a/docs/core/extensions/snippets/logging/console-formatter-simple/console-formatter-simple.csproj +++ b/docs/core/extensions/snippets/logging/console-formatter-simple/console-formatter-simple.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/core/extensions/snippets/logging/console-formatter-systemd/console-formatter-systemd.csproj b/docs/core/extensions/snippets/logging/console-formatter-systemd/console-formatter-systemd.csproj index fc0bc3029f375..880dae55b7ec2 100644 --- a/docs/core/extensions/snippets/logging/console-formatter-systemd/console-formatter-systemd.csproj +++ b/docs/core/extensions/snippets/logging/console-formatter-systemd/console-formatter-systemd.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/di-without-host/di-without-host.csproj b/docs/core/extensions/snippets/logging/di-without-host/di-without-host.csproj index 53b37d60de91f..6bb3809b510da 100644 --- a/docs/core/extensions/snippets/logging/di-without-host/di-without-host.csproj +++ b/docs/core/extensions/snippets/logging/di-without-host/di-without-host.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/docs/core/extensions/snippets/logging/getting-started-logger-message/getting-started-logger-message.csproj b/docs/core/extensions/snippets/logging/getting-started-logger-message/getting-started-logger-message.csproj index 62c91bb950a31..08df003cf2bd1 100644 --- a/docs/core/extensions/snippets/logging/getting-started-logger-message/getting-started-logger-message.csproj +++ b/docs/core/extensions/snippets/logging/getting-started-logger-message/getting-started-logger-message.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/extensions/snippets/logging/getting-started-open-telemetry/getting-started-open-telemetry.csproj b/docs/core/extensions/snippets/logging/getting-started-open-telemetry/getting-started-open-telemetry.csproj index c78d16e95d632..e329b1140655d 100644 --- a/docs/core/extensions/snippets/logging/getting-started-open-telemetry/getting-started-open-telemetry.csproj +++ b/docs/core/extensions/snippets/logging/getting-started-open-telemetry/getting-started-open-telemetry.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/getting-started-type-category-name/getting-started-type-category-name.csproj b/docs/core/extensions/snippets/logging/getting-started-type-category-name/getting-started-type-category-name.csproj index 62c91bb950a31..08df003cf2bd1 100644 --- a/docs/core/extensions/snippets/logging/getting-started-type-category-name/getting-started-type-category-name.csproj +++ b/docs/core/extensions/snippets/logging/getting-started-type-category-name/getting-started-type-category-name.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/extensions/snippets/logging/getting-started/getting-started.csproj b/docs/core/extensions/snippets/logging/getting-started/getting-started.csproj index 62c91bb950a31..08df003cf2bd1 100644 --- a/docs/core/extensions/snippets/logging/getting-started/getting-started.csproj +++ b/docs/core/extensions/snippets/logging/getting-started/getting-started.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/core/extensions/snippets/logging/library-authors/library-authors.csproj b/docs/core/extensions/snippets/logging/library-authors/library-authors.csproj index ffcea8d2fb2cb..0da2d08766059 100644 --- a/docs/core/extensions/snippets/logging/library-authors/library-authors.csproj +++ b/docs/core/extensions/snippets/logging/library-authors/library-authors.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/logger-message-generator/logger-message-generator.csproj b/docs/core/extensions/snippets/logging/logger-message-generator/logger-message-generator.csproj index 581eee6bb4af6..ee6ad58147722 100644 --- a/docs/core/extensions/snippets/logging/logger-message-generator/logger-message-generator.csproj +++ b/docs/core/extensions/snippets/logging/logger-message-generator/logger-message-generator.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/extensions/snippets/logging/worker-service-options/worker-service-options.csproj b/docs/core/extensions/snippets/logging/worker-service-options/worker-service-options.csproj index 1036776add983..c8d3e10dedbbd 100644 --- a/docs/core/extensions/snippets/logging/worker-service-options/worker-service-options.csproj +++ b/docs/core/extensions/snippets/logging/worker-service-options/worker-service-options.csproj @@ -10,6 +10,6 @@ - + diff --git a/docs/core/extensions/snippets/configuration/dependency-injection/LoggingMessageWriter.cs b/docs/core/extensions/snippets/overview/LoggingMessageWriter.cs similarity index 67% rename from docs/core/extensions/snippets/configuration/dependency-injection/LoggingMessageWriter.cs rename to docs/core/extensions/snippets/overview/LoggingMessageWriter.cs index c77548b6cc000..15731e37d45c5 100644 --- a/docs/core/extensions/snippets/configuration/dependency-injection/LoggingMessageWriter.cs +++ b/docs/core/extensions/snippets/overview/LoggingMessageWriter.cs @@ -1,6 +1,4 @@ -namespace DependencyInjection.Example; - -public class LoggingMessageWriter( +public class LoggingMessageWriter( ILogger logger) : IMessageWriter { public void Write(string message) => diff --git a/docs/core/extensions/snippets/overview/Program.cs b/docs/core/extensions/snippets/overview/Program.cs new file mode 100644 index 0000000000000..09f41bcefd4d3 --- /dev/null +++ b/docs/core/extensions/snippets/overview/Program.cs @@ -0,0 +1,35 @@ +HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); + +builder.Services.AddHostedService(); +builder.Services.AddSingleton(); + +using IHost host = builder.Build(); + +host.Run(); + +// +public class MessageWriter : IMessageWriter +{ + public void Write(string message) + { + Console.WriteLine($"MessageWriter.Write(message: \"{message}\")"); + } +} +// + +public interface IMessageWriter +{ + void Write(string message); +} + +public sealed class Worker(IMessageWriter messageWriter) : BackgroundService +{ + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + messageWriter.Write($"Worker running at: {DateTimeOffset.Now}"); + await Task.Delay(1_000, stoppingToken); + } + } +} diff --git a/docs/core/extensions/snippets/configuration/dependency-injection/dependency-injection.csproj b/docs/core/extensions/snippets/overview/dependency-injection.csproj similarity index 77% rename from docs/core/extensions/snippets/configuration/dependency-injection/dependency-injection.csproj rename to docs/core/extensions/snippets/overview/dependency-injection.csproj index 1cb9f690d0662..8f86351148293 100644 --- a/docs/core/extensions/snippets/configuration/dependency-injection/dependency-injection.csproj +++ b/docs/core/extensions/snippets/overview/dependency-injection.csproj @@ -4,12 +4,11 @@ net10.0 enable true - DependencyInjection.Example - - + + diff --git a/docs/core/extensions/snippets/primitives/change/tokens.csproj b/docs/core/extensions/snippets/primitives/change/tokens.csproj index e96ba71fb780f..7cbd660e433a7 100644 --- a/docs/core/extensions/snippets/primitives/change/tokens.csproj +++ b/docs/core/extensions/snippets/primitives/change/tokens.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/core/get-started.md b/docs/core/get-started.md index 58be4666d62f4..3e0d96bd70e3e 100644 --- a/docs/core/get-started.md +++ b/docs/core/get-started.md @@ -3,37 +3,60 @@ title: Get started with .NET description: Create a Hello World .NET app. author: adegeo ms.author: adegeo -ms.date: 10/21/2025 +ms.date: 01/12/2026 ms.custom: vs-dotnet, devdivchpfy22 ms.topic: tutorial ai-usage: ai-assisted --- # Get started with .NET -This article teaches you how to create and run a "Hello World!" app with [.NET](introduction.md). +This tutorial teaches you how to create and run your first .NET app using [file-based apps](./sdk/file-based-apps.md). You write a simple app and see the results of running your code. -## Create an application +In this tutorial, you: -First, download and install the [.NET SDK](https://dotnet.microsoft.com/download/dotnet) on your computer. +> [!div class="checklist"] +> +> * Launch a GitHub Codespace with a .NET development environment. +> * Create your first .NET app. +> * Run your app. -Next, open a terminal such as **PowerShell**, **Command Prompt**, or **bash**. +## Prerequisites -Type the following commands: +You must have one of the following options: -```dotnetcli -dotnet new console -o sample1 -cd sample1 -dotnet run -``` +- A GitHub account to use [GitHub Codespaces](https://github.com/codespaces). If you don't already have one, you can create a free account at [GitHub.com](https://github.com). +- A computer with the following tools installed: + - The [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). + - [Visual Studio Code](https://code.visualstudio.com/download). + - The [C# DevKit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit). -You should see the following output: +## Open Codespaces -```output -Hello World! -``` +To start a GitHub Codespace with the tutorial environment, open a browser window to the [tutorial codespace](https://github.com/dotnet/tutorial-codespace) repository. Select the green **Code** button, and the **Codespaces** tab. Then select the `+` sign to create a new Codespace using this environment. + +## Create and run your first app + +1. When your codespace loads, create a new file in the `tutorials` folder named `hello-world.cs`. +1. Open your new file. +1. Type or copy the following code into `hello-world.cs`: + + :::code language="csharp" source="./snippets/get-started/csharp/hello-world.cs" id="HelloWorld"::: + +1. In the integrated terminal window, make the `tutorials` folder the current folder, and run your app: + + ```dotnetcli + cd tutorials + dotnet hello-world.cs + ``` + +You ran your first .NET app. It's a simple app that prints the message "Hello, World!" It uses the method to print that message. `Console` is a type that represents the console window. `WriteLine` is a method of the `Console` type that prints a line of text to that text console. Congratulations! You created a simple .NET application. +## Cleanup resources + +GitHub automatically deletes your Codespace after 30 days of inactivity. If you plan to continue with .NET tutorials, you can leave your Codespace provisioned. If you're ready to download the .NET SDK to your computer, you can delete your Codespace. To delete your Codespace, open a browser window and navigate to [your Codespaces](https://github.com/codespaces). You should see a list of your codespaces in the window. Select the three dots (`...`) in the entry for the tutorial codespace and select **delete**. + ## Next steps Get started developing .NET applications by following a [step-by-step tutorial](../standard/get-started.md) or by watching [.NET 101 videos](https://www.youtube.com/playlist?list=PLdo4fOcmZ0oWoazjhXQzBKMrFuArxpW80) on YouTube. diff --git a/docs/core/install/linux-ubuntu-decision.md b/docs/core/install/linux-ubuntu-decision.md index 480202063ecdd..c9768aa0330b1 100644 --- a/docs/core/install/linux-ubuntu-decision.md +++ b/docs/core/install/linux-ubuntu-decision.md @@ -36,7 +36,7 @@ Canonical supports .NET versions in the built-in Ubuntu feed for the lifetime of Upgrading Ubuntu to 22.04 or later? Consider uninstalling .NET first. -If you used a package manager to install .NET from the Microsoft package repository, you'll end up with a package mix-up problem after upgrading Ubuntu. Now that Canonical publishes .NET to the package feeds for Ubuntu 22.04 (and later versions), the package manager won't know about the previously installed .NET version. The packages can't be upgraded to the latest .NET. First, uninstall them, then reinstall them from the [Ubuntu package repository]. +If you used a package manager to install .NET from the Microsoft package repository, you'll end up with a package mix-up problem after upgrading Ubuntu. Now that Canonical publishes .NET to the package feeds for Ubuntu 22.04 (and later versions), the package manager won't know about the previously installed .NET version. The packages can't be upgraded to the latest .NET. First, uninstall them, then reinstall them from the Ubuntu package repository. ## Decide how to install .NET diff --git a/docs/core/resilience/index.md b/docs/core/resilience/index.md index c0baaa7ca0d78..fc72a7fada3dc 100644 --- a/docs/core/resilience/index.md +++ b/docs/core/resilience/index.md @@ -9,9 +9,9 @@ ms.date: 10/20/2025 Resiliency is the ability of an app to recover from transient failures and continue to function. In the context of .NET programming, resilience is achieved by designing apps that can handle failures gracefully and recover quickly. To help build resilient apps in .NET, the following two packages are available on NuGet: | NuGet package | Description | -|--|--| -| [📦 Microsoft.Extensions.Resilience](https://www.nuget.org/packages/Microsoft.Extensions.Resilience) | This NuGet package provides mechanisms to harden apps against transient failures. | -| [📦 Microsoft.Extensions.Http.Resilience](https://www.nuget.org/packages/Microsoft.Extensions.Http.Resilience) | This NuGet package provides resilience mechanisms specifically for the class. | +|---------------|-------------| +| [📦 Microsoft.Extensions.Resilience](https://www.nuget.org/packages/Microsoft.Extensions.Resilience) | Provides mechanisms to harden apps against transient failures. The 10.x.x versions of this package support apps that target .NET, .NET Framework, and .NET Standard. | +| [📦 Microsoft.Extensions.Http.Resilience](https://www.nuget.org/packages/Microsoft.Extensions.Http.Resilience) | Provides resilience mechanisms specifically for the class. | These two NuGet packages are built on top of [Polly](https://github.com/App-vNext/Polly), which is a popular open-source project. Polly is a .NET resilience and transient fault-handling library that allows developers to express strategies such as [retry](/azure/architecture/patterns/retry), [circuit breaker](/azure/architecture/patterns/circuit-breaker), timeout, [bulkhead isolation](/azure/architecture/patterns/bulkhead), [rate-limiting](/azure/architecture/patterns/rate-limiting-pattern), fallback, and hedging in a fluent and thread-safe manner. @@ -20,7 +20,7 @@ These two NuGet packages are built on top of [Polly](https://github.com/App-vNex ## Get started -To get started with resilience in .NET, install the [Microsoft.Extensions.Resilience](https://www.nuget.org/packages/Microsoft.Extensions.Resilience) NuGet package. +To get started with resilience in .NET, install the latest version of the [Microsoft.Extensions.Resilience](https://www.nuget.org/packages/Microsoft.Extensions.Resilience) NuGet package. ### [.NET CLI](#tab/dotnet-cli) @@ -116,8 +116,7 @@ To use the resilience pipeline, call any of the available `Execute*` methods on The preceding code executes the delegate within the `ExecuteAsync` method. When there are failures, the configured strategies are executed. For example, if the `RetryStrategy` is configured to retry three times, the delegate is executed four times (one initial attempt plus three retry attempts) before the failure is propagated. -## Next steps +## See also -> [!div class="nextstepaction"] -> [Build resilient HTTP apps: Key development patterns](http-resilience.md) -> Consider the [challenges of idempotent handling of retried calls](/azure/architecture/reference-architectures/containers/aks-mission-critical/mission-critical-data-platform#idempotent-message-processing) +- [Build resilient HTTP apps: Key development patterns](http-resilience.md) +- [Challenges of idempotent handling of retried calls](/azure/architecture/reference-architectures/containers/aks-mission-critical/mission-critical-data-platform#idempotent-message-processing) diff --git a/docs/core/runtime-config/index.md b/docs/core/runtime-config/index.md index 7b9d4e4151227..6b75b687421cb 100644 --- a/docs/core/runtime-config/index.md +++ b/docs/core/runtime-config/index.md @@ -2,7 +2,7 @@ title: .NET Runtime config options description: Learn how to configure the .NET runtime using configuration settings. ms.topic: article -ms.date: 07/23/2021 +ms.date: 01/12/2026 --- # .NET runtime configuration settings @@ -12,7 +12,7 @@ ms.date: 07/23/2021 |---------------------------------------------------|----------------------------------------| | The [runtimeconfig.json file](#runtimeconfigjson) | Applies the setting to a specific app. Use this file if multiple instances of your app run at the same time on a single system, and you want to configure each for optimum performance. | | [MSBuild properties](#msbuild-properties) | Applies the setting to a specific app. MSBuild properties take precedence over settings in *runtimeconfig.json*. | -| [Environment variables](#environment-variables) | Applies the setting to all .NET apps. | +| [Environment variables](#environment-variables) | Applies the setting to all .NET apps. Starting in .NET 9, environment variables take precedence over both MSBuild properties and *runtimeconfig.json* settings. For more information, see [Environment variables take precedence in app runtime configuration settings](../compatibility/deployment/9.0/envvar-precedence.md). | Some configuration values can also be set programmatically by calling the method. @@ -114,6 +114,9 @@ MSBuild properties for configuring the behavior of the runtime are noted in the Environment variables can be used to supply some runtime configuration information. Configuration knobs specified as environment variables generally have the prefix `DOTNET_`. (For .NET Framework runtime configuration, use the `COMPlus_` prefix instead.) +> [!NOTE] +> Starting in .NET 9, environment variables take precedence over both MSBuild properties and *runtimeconfig.json* settings. For more information about this breaking change, see [Environment variables take precedence in app runtime configuration settings](../compatibility/deployment/9.0/envvar-precedence.md). + You can define environment variables from the Windows Control Panel, at the command line, or programmatically by calling the method on both Windows and Unix-based systems. The following examples show how to set an environment variable at the command line: diff --git a/docs/core/sdk/file-based-apps.md b/docs/core/sdk/file-based-apps.md index c50437641ab47..ab13736aa9ba3 100644 --- a/docs/core/sdk/file-based-apps.md +++ b/docs/core/sdk/file-based-apps.md @@ -80,6 +80,9 @@ Or use the `dotnet run` command followed by the name of the file: dotnet run file.cs ``` +> [!NOTE] +> When a project file exists in the current working directory, `dotnet run file.cs` without the `--file` option runs that project and passes `file.cs` as an argument to the target app to preserve backwards compatibility. + Or use the shorthand syntax: ```dotnetcli diff --git a/docs/core/snippets/get-started/csharp/get-started.csproj b/docs/core/snippets/get-started/csharp/get-started.csproj new file mode 100644 index 0000000000000..dfb40caafcf9a --- /dev/null +++ b/docs/core/snippets/get-started/csharp/get-started.csproj @@ -0,0 +1,10 @@ + + + + Exe + net10.0 + enable + enable + + + diff --git a/docs/core/snippets/get-started/csharp/hello-world.cs b/docs/core/snippets/get-started/csharp/hello-world.cs new file mode 100644 index 0000000000000..4ef8a2d0a1824 --- /dev/null +++ b/docs/core/snippets/get-started/csharp/hello-world.cs @@ -0,0 +1,3 @@ +// +Console.WriteLine("Hello, World!"); +// 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 508a603c2de3a..cbdf6a927a943 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 @@ -9,7 +9,7 @@ - + all diff --git a/docs/core/testing/unit-testing-best-practices.md b/docs/core/testing/unit-testing-best-practices.md index 353a8e74b06d1..ab10d1234c486 100644 --- a/docs/core/testing/unit-testing-best-practices.md +++ b/docs/core/testing/unit-testing-best-practices.md @@ -53,6 +53,9 @@ A high code coverage percentage isn't an indicator of success, and it doesn't im Several terms are used frequently in the context of unit testing: *fake*, *mock*, and *stub*. Unfortunately, these terms can be misapplied, so it's important to understand the correct usage. +> [!NOTE] +> Testing literature and tools use the terms *fake*, *stub*, and *mock* inconsistently. The following definitions represent common .NET usage where a test double can both return values and verify interactions. In classic xUnit and test double literature (for example, Fowler and Meszaros), those sources use these words more narrowly: a *stub* provides data, a *mock* verifies interactions, and a *fake* is a working alternative implementation. + - **Fake**: A fake is a generic term that can be used to describe either a stub or a mock object. Whether the object is a stub or a mock depends on the context in which the object is used. In other words, a fake can be a stub or a mock. - **Mock**: A mock object is a fake object in the system that decides whether or not a unit test passes or fails. A mock begins as a fake and remains a fake until it enters an `Assert` operation. diff --git a/docs/core/testing/unit-testing-mstest-writing-tests-attributes.md b/docs/core/testing/unit-testing-mstest-writing-tests-attributes.md index d4b0a66a4c769..72bbc7faf394c 100644 --- a/docs/core/testing/unit-testing-mstest-writing-tests-attributes.md +++ b/docs/core/testing/unit-testing-mstest-writing-tests-attributes.md @@ -63,6 +63,31 @@ public class MyTestClass } ``` +### `DiscoverInternalsAttribute` + +The [DiscoverInternals](xref:Microsoft.VisualStudio.TestTools.UnitTesting.DiscoverInternalsAttribute) attribute is applied at the assembly level to enable MSTest to discover test classes and test methods that are declared as `internal` rather than `public`. By default, MSTest only discovers public test classes and methods. When this attribute is present, both public and internal tests are discovered. + +This attribute is applied in the `AssemblyInfo.cs` file, the `MSTestSettings.cs` file or at the top of any file in the test assembly: + +```csharp +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[assembly: DiscoverInternals] + +namespace MyTests +{ + [TestClass] + internal class InternalTestClass // This class will be discovered + { + [TestMethod] + internal void InternalTestMethod() // This method will be discovered + { + Assert.IsTrue(true); + } + } +} +``` + ## Attributes used for data-driven testing Use the following elements to set up data-driven tests. For more information, see [Create a data-driven unit test](/visualstudio/test/how-to-create-a-data-driven-unit-test) and [Use a configuration file to define a data source](/visualstudio/test/walkthrough-using-a-configuration-file-to-define-a-data-source). @@ -184,9 +209,247 @@ public class TestClass } ``` +Starting with MSTest v3.8, you can use the property to conditionally ignore specific test cases: + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod] + [DataRow(1, 2)] + [DataRow(3, 4, IgnoreMessage = "Temporarily disabled")] + [DataRow(5, 6)] + public void TestMethod(int i, int j) + { + // Only the first and third data rows will run + // The second data row is skipped with the provided message + } +} +``` + +### `DynamicDataAttribute` + +The [DynamicData](xref:Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataAttribute) attribute allows you to run the same test method with data provided by a field, a property, or a method. This is useful when you need to generate test data dynamically or when the test data is too complex to define inline with . + +The attribute requires the name of a field, a property, or method that provides the test data. The data source can return any of the following types: + +- `IEnumerable` - each `object[]` represents the arguments for one test case +- `IEnumerable` - each tuple represents the arguments for one test case (for example, `IEnumerable<(int, string)>`) +- `IEnumerable>` - each `Tuple` represents the arguments for one test case +- `IEnumerable` - provides additional control over test case metadata (see [TestDataRow](#testdatarow) subsection) + +> [!NOTE] +> Any collection type that inherits from `IEnumerable` works, not just `IEnumerable` itself. For example, `List`, `object[][]`, or custom collection types are all supported. + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod] + [DynamicData(nameof(GetTestData))] + public void TestMethod(int value1, string value2) + { + // Test implementation + } + + public static IEnumerable GetTestData() + { + yield return new object[] { 1, "first" }; + yield return new object[] { 2, "second" }; + yield return new object[] { 3, "third" }; + } +} +``` + +By default, the looks for the data source in the same class as the test method. You can specify a different class using the `DynamicDataSourceType` parameter: + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod] + [DynamicData(nameof(TestDataProvider.GetTestData), typeof(TestDataProvider))] + public void TestMethod(int value1, string value2) + { + // Test implementation + } +} + +public class TestDataProvider +{ + public static IEnumerable GetTestData() + { + yield return new object[] { 1, "first" }; + yield return new object[] { 2, "second" }; + } +} +``` + +You can also use properties or fields instead of methods: + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod] + [DynamicData(nameof(TestData))] + public void TestMethod(int value1, string value2) + { + // Test implementation + } + + public static IEnumerable TestData => new[] + { + new object[] { 1, "first" }, + new object[] { 2, "second" }, + new object[] { 3, "third" } + }; + + // Fields are also supported + public static IEnumerable TestDataField = new[] + { + new object[] { 10, "ten" }, + new object[] { 20, "twenty" } + }; +} +``` + +The also supports the property to customize how test cases appear in Test Explorer. You can specify the display name format using the to reference a method that generates the display name: + +```csharp +using System.Reflection; + +[TestClass] +public class TestClass +{ + [TestMethod] + [DynamicData(nameof(GetTestData), DynamicDataDisplayName = nameof(GetDisplayName))] + public void TestMethod(int value1, string value2) + { + // Test implementation + } + + public static IEnumerable GetTestData() + { + yield return new object[] { 1, "first" }; + yield return new object[] { 2, "second" }; + } + + public static string GetDisplayName(MethodInfo methodInfo, object[] data) + { + return $"{methodInfo.Name} - {data[0]} and {data[1]}"; + } +} +``` + +> [!NOTE] +> The display name method must be `public static`, return a `string`, and accept two parameters: `MethodInfo` and `object[]`. + +Starting with MSTest v3.8, you can use the property to conditionally ignore all test cases generated by the dynamic data source: + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod] + [DynamicData(nameof(GetTestData), IgnoreMessage = "Feature not ready")] + public void TestMethod(int value1, string value2) + { + // All test cases from GetTestData will be skipped + } + + public static IEnumerable GetTestData() + { + yield return new object[] { 1, "first" }; + yield return new object[] { 2, "second" }; + } +} +``` + +> [!NOTE] +> To ignore individual test cases when using , use the `TestDataRow` class with its `IgnoreMessage` property (see [TestDataRow](#testdatarow) section). + +#### TestDataRow + +The `TestDataRow` class provides enhanced control over test data in data-driven tests. When using `IEnumerable>` as the return type for your dynamic data source, you can specify additional metadata for each test case, such as custom display names and test properties. + +`TestDataRow` offers the following benefits: + +- **Custom display names**: Set a unique display name for each test case using the `DisplayName` property. +- **Test categories**: Attach metadata to individual test cases using the `TestCategories` property. +- **Type-safe data**: Use the generic `TestDataRow` to provide strongly-typed test data. + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod] + [DynamicData(nameof(GetTestDataRows))] + public void TestMethod(int value1, string value2) + { + // Test implementation + } + + public static IEnumerable GetTestDataRows() + { + yield return new TestDataRow((1, "first")) + { + DisplayName = "Test Case 1: Basic scenario" + }; + + yield return new TestDataRow((2, "second")) + { + DisplayName = "Test Case 2: Edge case", + TestProperties = { ["Priority"] = "High", ["Category"] = "Critical" } + }; + } +} +``` + +### `UnfoldingStrategy` property + +Data-driven test attributes like and support the property, which controls how test cases appear in Test Explorer and TRX results. This property also determines whether individual test cases can be run independently. + +The `UnfoldingStrategy` property accepts the following values: + +- (default): MSTest automatically determines whether to unfold test cases based on the number of data rows. Test cases are collapsed (folded) when there are many data rows to avoid cluttering Test Explorer, and unfolded when there are few data rows for better visibility. +- : All test cases are expanded and shown individually in Test Explorer and TRX results. Each test case can be run independently. +- : All test cases are collapsed into a single test node. Individual test cases can't be run independently; the entire data-driven test runs as one unit. + +For most scenarios, the default `Auto` behavior provides the best balance between usability and performance. Changing this setting is considered an advanced scenario and should only be done when you have specific requirements, such as non-deterministic data source or known limitations or bugs of MSTest. + +```csharp +[TestClass] +public class TestClass +{ + [TestMethod(UnfoldingStrategy = TestDataSourceUnfoldingStrategy.Unfold)] // Force unfolding/expanding + [DataRow(1)] + [DataRow(2)] + [DataRow(3)] + public void TestMethodWithUnfolding(int value) + { + // Each test case appears individually in Test Explorer + } + + [TestMethod(UnfoldingStrategy = TestDataSourceUnfoldingStrategy.Fold)] // Force folding/collapsing + [DynamicData(nameof(GetData))] + public void TestMethodWithFolding(int value) + { + // All test cases appear as a single collapsed node + } + + public static IEnumerable GetData() + { + yield return new object[] { 1 }; + yield return new object[] { 2 }; + yield return new object[] { 3 }; + } +} +``` + ## Attributes used to provide initialization and cleanups -Setup and cleanup that is common to multiple tests can be extracted to a separate method, and marked with one of the attributes listed below, to run it at appropriate time, for example before every test. For more information, see [Anatomy of a unit test](/previous-versions/ms182517(v=vs.110)). +Setup and cleanup that's common to multiple tests can be extracted to a separate method and marked with one of the attributes listed in the following section, to run it at appropriate time, for example, before every test. For more information, see [Anatomy of a unit test](/previous-versions/ms182517(v=vs.110)). ### Assembly level @@ -263,38 +526,85 @@ public class MyTestClass } ``` -## Attributes used to control test execution +### Global test level -The following attributes can be used to modify the way tests are executed. +The [GlobalTestInitialize](xref:Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestInitializeAttribute) attribute is called right before every test method in the assembly and the [GlobalTestCleanup](xref:Microsoft.VisualStudio.TestTools.UnitTesting.GlobalTestCleanupAttribute) is called right after every test method in the assembly. These attributes were introduced in MSTest 3.10.0. -### `TimeoutAttribute` +These attributes provide a way to define initialization and cleanup logic that applies to all test methods across the entire assembly, without having to add the same initialization/cleanup code in every test class. -The [Timeout](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TimeoutAttribute) attribute can be used to specify the maximum time in milliseconds that a test method is allowed to run. If the test method runs longer than the specified time, the test will be aborted and marked as failed. +The methods marked with these attributes must be defined as `public static void`, `static Task` or `static ValueTask`, in a class marked with , must be non-generic, must have exactly one parameter of type , and can appear multiple times across different test classes in the assembly. -This attribute can be applied to any test method or any fixture method (initialization and cleanup methods). It is also possible to specify the timeout globally for either all test methods or all test fixture methods by using the [timeout properties of the runsettings file](./unit-testing-mstest-configure.md#mstest-element). +```csharp +[TestClass] +public class MyTestClass +{ + [GlobalTestInitialize] + public static void GlobalTestInitialize(TestContext testContext) + { + // This runs before every test method in the assembly + } + + [GlobalTestCleanup] + public static void GlobalTestCleanup(TestContext testContext) + { + // This runs after every test method in the assembly + } +} +``` > [!NOTE] -> The timeout is not guaranteed to be precise. The test will be aborted after the specified time has passed, but it may take longer before the step is cancelled. +> Multiple methods with these attributes in the assembly are allowed, but there's no guarantee of the order in which they'll execute. The isn't supported on methods with the . -When using the timeout feature, a separate thread/task is created to run the test method. The main thread/task is responsible for monitoring the timeout and unobserving the method thread/task if the timeout is reached. +## Attributes used to control test execution -Starting with MSTest 3.6, it is possible to specify property on the attribute (or globally through runsettings) to enable cooperative cancellation. In this mode, the method is responsible for checking the cancellation token and aborting the test if it is signaled as you would do in a typical `async` method. This mode is more performant and allows for more precise control over the cancellation process. This mode can be applied to both async and sync methods. +The following attributes can be used to modify the way tests are executed. + +### Threading attributes -### `STATestClassAttribute` +These attributes control the threading model for test execution. + +#### `STATestClassAttribute` When applied to a test class, the [STATestClass](xref:Microsoft.VisualStudio.TestTools.UnitTesting.STATestClassAttribute) attribute indicates that all test methods (and the `[ClassInitialize]` and `[ClassCleanup]` methods) in the class should be run in a single-threaded apartment (STA). This attribute is useful when the test methods interact with COM objects that require STA. > [!NOTE] > This is only supported on Windows and in version 3.6 and later. -### `STATestMethodAttribute` +#### `STATestMethodAttribute` When applied to a test method, the [STATestMethod](xref:Microsoft.VisualStudio.TestTools.UnitTesting.STATestMethodAttribute) attribute indicates that the test method should be run in a single-threaded apartment (STA). This attribute is useful when the test method interacts with COM objects that require STA. > [!NOTE] > This is only supported on Windows and in version 3.6 and later. -### `ParallelizeAttribute` +#### `UITestMethodAttribute` + +When applied to a test method, the `UITestMethod` attribute indicates that the test method should be scheduled on the UI thread of the platform. This attribute is specifically designed for testing UWP (Universal Windows Platform) and WinUI applications that require UI thread access. + +This attribute is useful when testing UI components, controls, or any code that must run on the UI thread to interact with the application's visual elements. + +```csharp +[TestClass] +public class MyUITestClass +{ + [UITestMethod] + public void TestUIComponent() + { + // This test runs on the UI thread, allowing interaction with UI elements + var button = new Button(); + Assert.IsNotNull(button); + } +} +``` + +> [!NOTE] +> This attribute is available for UWP and WinUI applications and requires the appropriate MSTest adapter for these platforms. + +### Parallelization attributes + +These attributes control whether and how tests run in parallel. + +#### `ParallelizeAttribute` By default, MSTest runs tests in a sequential order. The assembly level attribute [Parallelize](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ParallelizeAttribute) attribute can be used to run tests in parallel. You can specify if the parallelism should be at [class level](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope.ClassLevel) (multiple classes can be run in parallel but tests in a given class are run sequentially) or at [method level](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ExecutionScope.MethodLevel). @@ -302,21 +612,182 @@ It's also possible to specify the maximum number of threads to use for parallel It is also possible to specify the parallelism through the [parallelization properties of the runsettings file](./unit-testing-mstest-configure.md#mstest-element). -### `DoNotParallelizeAttribute` +#### `DoNotParallelizeAttribute` The [DoNotParallelize](xref:Microsoft.VisualStudio.TestTools.UnitTesting.DoNotParallelizeAttribute) attribute can be used to prevent parallel execution of tests in a given assembly. This attribute can be applied at the assembly level, class level or method level. > [!NOTE] > By default, MSTest runs tests in sequential order so you only need to use this attribute if you have applied the assembly level [Parallelize](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ParallelizeAttribute) attribute. -### `RetryAttribute` +### Timeout and retry attributes + +These attributes control test execution time limits and retry behavior. + +#### `TimeoutAttribute` + +The [Timeout](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TimeoutAttribute) attribute can be used to specify the maximum time in milliseconds that a test method is allowed to run. If the test method runs longer than the specified time, the test is aborted and marked as failed. + +This attribute can be applied to any test method or any fixture method (initialization and cleanup methods). It is also possible to specify the timeout globally for either all test methods or all test fixture methods by using the [timeout properties of the runsettings file](./unit-testing-mstest-configure.md#mstest-element). + +> [!NOTE] +> The timeout isn't guaranteed to be precise. The test is be aborted after the specified time passes, but it might take longer before the step is cancelled. + +When using the timeout feature, a separate thread/task is created to run the test method. The main thread/task is responsible for monitoring the timeout and unobserving the method thread/task if the timeout is reached. + +Starting with MSTest 3.6, it is possible to specify property on the attribute (or globally through runsettings) to enable cooperative cancellation. In this mode, the method is responsible for checking the cancellation token and aborting the test if it is signaled as you would do in a typical `async` method. This mode is more performant and allows for more precise control over the cancellation process. This mode can be applied to both async and sync methods. -The `Retry` attribute was introduced in MSTest 3.8. This attribute causes the test method to be retried when it fails or timeouts. It allows you to specify the maximum number of retry attempts, the time delay between retries, and a delay backoff type, which is either constant or exponential. +#### `RetryAttribute` + +The [Retry](xref:Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute) attribute was introduced in MSTest 3.8. This attribute causes the test method to be retried when it fails or timeouts. It allows you to specify the maximum number of retry attempts, the time delay between retries, and a delay backoff type, which is either constant, or exponential. Only one `RetryAttribute` is expected to be present on a test method, and `RetryAttribute` cannot be used on methods that are not marked with [TestMethod](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute). +```csharp +[TestClass] +public class MyTestClass +{ + [TestMethod] + [Retry(3)] // Retry up to 3 times if the test fails + public void FlakeyTest() + { + // Test implementation that might occasionally fail + } +} +``` + +> [!NOTE] +> `RetryAttribute` derives from an abstract [RetryBaseAttribute](xref:Microsoft.VisualStudio.TestTools.UnitTesting.RetryBaseAttribute). You can also create your own retry implementations if the built-in `RetryAttribute` isn't suitable for your needs. + +### Conditional execution attributes + +These attributes control whether tests run based on specific conditions. + +#### `ConditionBaseAttribute` + +The [ConditionBase](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute) attribute is an abstract base class used to conditionally control whether a test class or test method runs or is ignored. This attribute provides the foundation for creating custom conditional execution logic. + +Derived classes, such as [CIConditionAttribute](xref:Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute), [IgnoreAttribute](xref:Microsoft.VisualStudio.TestTools.UnitTesting.IgnoreAttribute), and [OSConditionAttribute](xref:Microsoft.VisualStudio.TestTools.UnitTesting.OSConditionAttribute), implement specific conditions to determine whether tests should be executed. + +> [!NOTE] +> This attribute isn't inherited. Applying it to a base class doesn't affect derived classes. + +#### `CIConditionAttribute` + +The [CICondition](xref:Microsoft.VisualStudio.TestTools.UnitTesting.CIConditionAttribute) attribute is used to conditionally run or ignore a test class or test method based on whether the test is running in a continuous integration (CI) environment. This attribute derives from [ConditionBaseAttribute](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute). + +You can specify the [ConditionMode](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ConditionMode) to either include (run only in CI) or exclude (skip in CI): + +```csharp +[TestClass] +public class MyTestClass +{ + [TestMethod] + [CICondition] // Run only in CI (default behavior, equivalent to `[CICondition(ConditionMode.Include)]`) + public void CIOnlyTest() + { + // This test runs only when executed in a CI environment + } + + [TestMethod] + [CICondition(ConditionMode.Exclude)] // Skip in CI + public void LocalOnlyTest() + { + // This test is skipped when running in a CI environment + } +} +``` + +> [!NOTE] +> This attribute isn't inherited. Applying it to a base class doesn't affect derived classes. + +#### `OSConditionAttribute` + +The [OSCondition](xref:Microsoft.VisualStudio.TestTools.UnitTesting.OSConditionAttribute) attribute is used to conditionally run or ignore a test class or test method based on the operating system where the test is running. This attribute derives from [ConditionBaseAttribute](xref:Microsoft.VisualStudio.TestTools.UnitTesting.ConditionBaseAttribute). + +You can specify which operating systems the test supports or doesn't support using the [OperatingSystems](xref:Microsoft.VisualStudio.TestTools.UnitTesting.OperatingSystems) flags enum, which includes `Windows`, `Linux`, `OSX` (macOS), and `FreeBSD`. You can combine multiple operating systems using the bitwise OR operator. + +```csharp +[TestClass] +public class MyTestClass +{ + [TestMethod] + [OSCondition(OperatingSystems.Windows)] // Run only on Windows + public void WindowsOnlyTest() + { + // This test runs only on Windows + } + + [TestMethod] + [OSCondition(OperatingSystems.Linux | OperatingSystems.OSX)] // Run on Linux or macOS + public void UnixLikeTest() + { + // This test runs on Linux or macOS + } + + [TestMethod] + [OSCondition(ConditionMode.Exclude, OperatingSystems.Windows)] // Skip on Windows + public void SkipOnWindowsTest() + { + // This test is skipped on Windows + } +} +``` + > [!NOTE] -> `RetryAttribute` derives from an abstract `RetryBaseAttribute`. You can also create your own retry implementations if the built-in `RetryAttribute` doesn't suite your needs. +> This attribute isn't inherited. Applying it to a base class doesn't affect derived classes. + +#### `IgnoreAttribute` + +The [Ignore](xref:Microsoft.VisualStudio.TestTools.UnitTesting.IgnoreAttribute) attribute marks a test class or test method to be skipped during test execution. This attribute is useful for temporarily disabling tests without removing them from the codebase. + +You can optionally provide a reason for ignoring the test: + +```csharp +[TestClass] +public class MyTestClass +{ + [TestMethod] + [Ignore] + public void TemporarilyDisabledTest() + { + // This test is skipped + } + + [TestMethod] + [Ignore("Waiting for bug fix")] + public void TestWithReason() + { + // This test is skipped with a reason + } +} +``` + +When ignoring a test due to a specific work item or issue, consider using the [WorkItem](xref:Microsoft.VisualStudio.TestTools.UnitTesting.WorkItemAttribute) or [GitHubWorkItem](xref:Microsoft.VisualStudio.TestTools.UnitTesting.GitHubWorkItemAttribute) attributes to provide a structured link to the ticket instead of a simple string. These attributes provide better traceability and can be used to generate reports linking tests to specific work items: + +```csharp +[TestClass] +public class MyTestClass +{ + [TestMethod] + [Ignore("Waiting for fix")] + [WorkItem(12345)] // Links to work item 12345 in your tracking system + public void TestWithWorkItem() + { + // This test is skipped and linked to a work item + } + + [TestMethod] + [Ignore("Known issue")] + [GitHubWorkItem("https://github.com/owner/repo/issues/42")] // Links to GitHub issue + public void TestWithGitHubIssue() + { + // This test is skipped and linked to a GitHub issue + } +} +``` + +> [!NOTE] +> This attribute isn't inherited. Applying it to a base class doesn't affect derived classes. ## Utilities attributes @@ -361,16 +832,19 @@ The [ExpectedException](xref:Microsoft.VisualStudio.TestTools.UnitTesting.Expect The following attributes and the values assigned to them appear in the `Visual Studio` **Properties** window for a particular test method. These attributes aren't meant to be accessed through the code of the test. Instead, they affect the ways the test is used or run, either by you through the IDE of Visual Studio, or by the Visual Studio test engine. For example, some of these attributes appear as columns in the **Test Manager** window and **Test Results** window, which means that you can use them to group and sort tests and test results. One such attribute is , which you use to add arbitrary metadata to tests. -For example, you could use it to store the name of a "test pass" that this test covers, by marking the test with `[TestProperty("Feature", "Accessibility")]`. Or, you could use it to store an indicator of the kind of test It's with `[TestProperty("ProductMilestone", "42")]`. The property you create by using this attribute, and the property value you assign, are both displayed in the Visual Studio **Properties** window under the heading **Test specific**. +For example, you could use it to store the name of a "test pass" that this test covers, by marking the test with `[TestProperty("Feature", "Accessibility")]`. Or, you could use it to store an indicator of the kind of test it's with `[TestProperty("ProductMilestone", "42")]`. The property you create by using this attribute, and the property value you assign, are both displayed in the Visual Studio **Properties** window under the heading **Test specific**. - -- +- - - - - - +> [!NOTE] +> For information about the , see the [Conditional execution attributes](#conditional-execution-attributes) section. + The attributes below relate the test method that they decorate to entities in the project hierarchy of a `Team Foundation Server` team project: - diff --git a/docs/core/tools/dotnet-environment-variables.md b/docs/core/tools/dotnet-environment-variables.md index c58e6863b1057..7eb7a28f4c779 100644 --- a/docs/core/tools/dotnet-environment-variables.md +++ b/docs/core/tools/dotnet-environment-variables.md @@ -6,7 +6,7 @@ ms.date: 11/20/2025 # .NET environment variables -In this article, you'll learn about the environment variables used by .NET. Some environment variables are used by the .NET runtime, while others are only used by the .NET SDK and .NET CLI. Some environment variables are used by all three components. +This article lists the environment variables used by .NET. Some environment variables are used by the .NET runtime, while others are only used by the .NET SDK and .NET CLI. Some environment variables are used by all three components. ## .NET runtime environment variables @@ -81,7 +81,7 @@ Applications can enable the invariant mode in any of the following ways: 1. By setting environment variable value `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT` to `true` or `1`. > [!IMPORTANT] -> A value set in the project file or _runtimeconfig.json_ has a higher priority than the environment variable. +> In .NET 9 and later versions, environment variables have a higher priority than values set in the project file or _runtimeconfig.json_. For more information, see [.NET Globalization Invariant Mode](https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md). diff --git a/docs/core/tools/dotnet-test.md b/docs/core/tools/dotnet-test.md index 9e4c6317081a9..500b93238e1c5 100644 --- a/docs/core/tools/dotnet-test.md +++ b/docs/core/tools/dotnet-test.md @@ -16,6 +16,9 @@ ai-usage: ai-assisted The `dotnet test` command builds the solution and runs the tests with either VSTest or Microsoft Testing Platform (MTP). The test runner you use determines the available command-line options and behavior. +> [!NOTE] +> Test runner selection is available starting with .NET 10 SDK. In earlier versions of .NET, tests are always executed with VSTest. + ### Choosing a test runner To enable Microsoft.Testing.Platform, you need to specify the test runner in the [`global.json`](global-json.md) file: @@ -38,7 +41,7 @@ To enable Microsoft.Testing.Platform, you need to specify the test runner in the The available command-line options, behavior, and capabilities differ depending on which test runner you use: -- **[dotnet test with VSTest](dotnet-test-vstest.md)** - The traditional test platform, available in .NET 6 SDK and later. Provides comprehensive test discovery, filtering, and result reporting capabilities. +- **[dotnet test with VSTest](dotnet-test-vstest.md)** - The traditional test platform, available in .NET 6 SDK and later. This is the default and only test runner in versions earlier than .NET 10 SDK. Provides comprehensive test discovery, filtering, and result reporting capabilities. - **[dotnet test with MTP](dotnet-test-mtp.md)** - The modern testing platform, available in .NET 10 SDK and later. Offers faster test execution and more flexible test module selection. diff --git a/docs/core/tutorials/debugging-with-visual-studio.md b/docs/core/tutorials/debugging-with-visual-studio.md index d7e0042308df9..cb6a3aa95dba3 100644 --- a/docs/core/tutorials/debugging-with-visual-studio.md +++ b/docs/core/tutorials/debugging-with-visual-studio.md @@ -1,7 +1,7 @@ --- title: Debug a .NET console application using Visual Studio description: Learn how to debug a .NET console app using Visual Studio. -ms.date: 10/23/2025 +ms.date: 01/14/2026 ai-usage: ai-assisted dev_langs: - "csharp" @@ -43,7 +43,7 @@ A *breakpoint* temporarily interrupts the execution of the application before th As the following image shows, Visual Studio indicates the line on which the breakpoint is set by highlighting it and displaying a red dot in the left margin. - :::image type="content" source="./media/debugging-with-visual-studio/set-breakpoint-in-editor-net6.png" alt-text="Visual Studio Program window with breakpoint set"::: + :::image type="content" source="./media/debugging-with-visual-studio/set-breakpoint-in-editor.png" alt-text="Visual Studio Program window with breakpoint set"::: 1. Press F5 to run the program in Debug mode. Another way to start debugging is by choosing **Debug** > **Start Debugging** from the menu. @@ -51,7 +51,7 @@ A *breakpoint* temporarily interrupts the execution of the application before th 1. Program execution stops when it reaches the breakpoint and before the `Console.WriteLine` method executes. The **Locals** window displays the values of variables that are defined in the currently executing method. - :::image type="content" source="./media/debugging-with-visual-studio/breakpoint-hit-net6.png" alt-text="Screenshot of a breakpoint in Visual Studio"::: + :::image type="content" source="./media/debugging-with-visual-studio/breakpoint-hit.png" alt-text="Screenshot of a breakpoint in Visual Studio"::: ## Use the Immediate window @@ -61,18 +61,16 @@ The **Immediate** window lets you interact with the application you're debugging 1. Enter `name = "Gracie"` in the **Immediate** window and press the Enter key. -1. Enter `currentDate = DateTime.Parse("2019-11-16T17:25:00Z").ToUniversalTime()` in the **Immediate** window and press the Enter key. +1. Enter `currentDate = DateTime.Parse("2026-01-14T17:25:00Z").ToUniversalTime()` in the **Immediate** window and press the Enter key. The **Immediate** window displays the value of the string variable and the properties of the value. In addition, the values of the variables are updated in the **Locals** window. - :::image type="content" source="./media/debugging-with-visual-studio/locals-immediate-window.png" alt-text="Locals and Immediate Windows in Visual Studio 2019"::: + :::image type="content" source="./media/debugging-with-visual-studio/locals-immediate-window.png" alt-text="Locals and Immediate Windows in Visual Studio"::: 1. Press F5 to continue program execution. Another way to continue is by choosing **Debug** > **Continue** from the menu. The values displayed in the console window correspond to the changes you made in the **Immediate** window. - :::image type="content" source="./media/debugging-with-visual-studio/console-window.png" alt-text="Console window showing the entered values"::: - 1. Press any key to exit the application and stop debugging. ## Set a conditional breakpoint @@ -81,9 +79,9 @@ The program displays the string that the user enters. What happens if the user d 1. Right-click on the red dot that represents the breakpoint. In the context menu, select **Conditions** to open the **Breakpoint Settings** dialog. Select the box for **Conditions** if it's not already selected. - :::image type="content" source="./media/debugging-with-visual-studio/breakpoint-settings-net6.png" alt-text="Editor showing breakpoint settings panel - C#"::: + :::image type="content" source="./media/debugging-with-visual-studio/breakpoint-settings.png" alt-text="Editor showing breakpoint settings panel - C#"::: -1. For the **Conditional Expression**, enter the following code in the field that shows example code that tests if `x` is 5. +1. For the **Conditional Expression**, enter the following code in the text field. ```csharp string.IsNullOrEmpty(name) @@ -135,25 +133,13 @@ Visual Studio also allows you to step line by line through a program and monitor Visual Studio highlights and displays an arrow beside the next line of execution. - C# - - :::image type="content" source="./media/debugging-with-visual-studio/step-into-method-net6.png" alt-text="Visual Studio step into method - C#"::: - - Visual Basic - - :::image type="content" source="./media/debugging-with-visual-studio/vb-step-into-method.png" alt-text="Visual Studio step into method - Visual Basic"::: + :::image type="content" source="./media/debugging-with-visual-studio/step-into-method.png" alt-text="Visual Studio step into method - C#"::: At this point, the **Locals** window shows that the `args` array is empty, and `name` and `currentDate` have default values. In addition, Visual Studio has opened a blank console window. 1. Press F11. Visual Studio now highlights the next line of execution. The **Locals** window is unchanged, and the console window remains blank. - C# - - :::image type="content" source="./media/debugging-with-visual-studio/step-into-source-method-net6.png" alt-text="Visual Studio step in method source - C#"::: - - Visual Basic - - :::image type="content" source="./media/debugging-with-visual-studio/vb-step-into-source-method.png" alt-text="Visual Studio step into method source - Visual Basic"::: + :::image type="content" source="./media/debugging-with-visual-studio/step-into-source-method.png" alt-text="Visual Studio step in method source - C#"::: 1. Press F11. Visual Studio highlights the statement that includes the `name` variable assignment. The **Locals** window shows that `name` is `null`, and the console window displays the string "What is your name?". diff --git a/docs/core/tutorials/library-with-visual-studio.md b/docs/core/tutorials/library-with-visual-studio.md index e493e5489337b..efb52170df955 100644 --- a/docs/core/tutorials/library-with-visual-studio.md +++ b/docs/core/tutorials/library-with-visual-studio.md @@ -1,7 +1,7 @@ --- title: Create a .NET class library using Visual Studio description: Learn how to create a .NET class library using Visual Studio. -ms.date: 10/23/2025 +ms.date: 01/13/2026 ai-usage: ai-assisted dev_langs: - "csharp" @@ -12,35 +12,35 @@ ms.custom: vs-dotnet In this tutorial, you create a simple class library that contains a single string-handling method. -A *class library* defines types and methods that are called by an application. If the library targets .NET Standard 2.0, it can be called by any .NET implementation (including .NET Framework) that supports .NET Standard 2.0. If the library targets .NET 8, it can be called by any application that targets .NET 8. This tutorial shows how to target .NET 8. +A *class library* defines types and methods that an application calls. If the library targets .NET Standard 2.0, any .NET implementation (including .NET Framework) that supports .NET Standard 2.0 can call it. If the library targets .NET 10, any application that targets .NET 10 can call it. This tutorial shows how to target .NET 10. When you create a class library, you can distribute it as a NuGet package or as a component bundled with the application that uses it. ## Prerequisites -- [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link) with the **.NET desktop development** workload installed. The .NET SDK is automatically installed when you select this workload. +- [Visual Studio 2026 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link) with the **.NET desktop development** workload installed. The .NET SDK is automatically installed when you select this workload. For more information, see [Install the .NET SDK with Visual Studio](../install/windows.md#install-with-visual-studio). ## Create a solution -Start by creating a blank solution to put the class library project in. A Visual Studio solution serves as a container for one or more projects. You'll add related projects to the same solution. +Start by creating a blank solution to hold the class library project. A Visual Studio solution serves as a container for one or more projects. Add related projects to the same solution. To create the blank solution: 1. Start Visual Studio. -2. On the start window, choose **Create a new project**. +1. On the start window, choose **Create a new project**. -3. On the **Create a new project** page, enter **solution** in the search box. Choose the **Blank Solution** template, and then choose **Next**. +1. On the **Create a new project** page, enter **solution** in the search box. Choose the **Blank Solution** template, and then choose **Next**. :::image type="content" source="media/library-with-visual-studio/blank-solution.png" alt-text="Blank solution template in Visual Studio"::: -4. On the **Configure your new project** page, enter **ClassLibraryProjects** in the **Solution name** box. Then choose **Create**. +1. On the **Configure your new project** page, enter **ClassLibraryProjects** in the **Solution name** box. Then choose **Create**. ## Create a class library project -1. Add a new .NET class library project named "StringLibrary" to the solution. +1. Add a new .NET class library project named **StringLibrary** to the solution. 1. Right-click on the solution in **Solution Explorer** and select **Add** > **New Project**. @@ -48,13 +48,13 @@ To create the blank solution: 1. On the **Configure your new project** page, enter **StringLibrary** in the **Project name** box, and then choose **Next**. - 1. On the **Additional information** page, select **.NET 8**, and then choose **Create**. + 1. On the **Additional information** page, select **.NET 10**, and then choose **Create**. -1. Check to make sure that the library targets the correct version of .NET. Right-click on the library project in **Solution Explorer**, and then select **Properties**. The **Target Framework** text box shows that the project targets .NET 8.0. +1. Check to make sure that the library targets the correct version of .NET. Right-click on the library project in **Solution Explorer**, and then select **Properties**. The **Target Framework** text box shows that the project targets .NET 10.0. -1. If you're using Visual Basic, clear the text in the **Root namespace** text box. +1. If you're using Visual Basic, clear the text in the **Default namespace** text box. - :::image type="content" source="./media/library-with-visual-studio/vb/library-project-properties-net8.png" alt-text="Project properties for the class library"::: + :::image type="content" source="./media/library-with-visual-studio/vb/library-project-properties.png" alt-text="Project properties for the class library"::: For each project, Visual Basic automatically creates a namespace that corresponds to the project name. In this tutorial, you define a top-level namespace by using the [`namespace`](../../visual-basic/language-reference/statements/namespace-statement.md) keyword in the code file. @@ -71,9 +71,9 @@ To create the blank solution: ## Add a console app to the solution -Add a console application that uses the class library. The app will prompt the user to enter a string and report whether the string begins with an uppercase character. +Add a console application that uses the class library. The app prompts the user to enter a string and reports whether the string begins with an uppercase character. -1. Add a new .NET console application named "ShowCase" to the solution. +1. Add a new .NET console application named **ShowCase** to the solution. 1. Right-click on the solution in **Solution Explorer** and select **Add** > **New project**. @@ -83,7 +83,7 @@ Add a console application that uses the class library. The app will prompt the u 1. On the **Configure your new project** page, enter **ShowCase** in the **Project name** box. Then choose **Next**. - 1. On the **Additional information** page, select **.NET 8** in the **Framework** box. Then choose **Create**. + 1. On the **Additional information** page, select **.NET 10** in the **Framework** box. Then choose **Create**. 1. In the code window for the *Program.cs* or *Program.vb* file, replace all of the code with the following code. @@ -116,7 +116,7 @@ Initially, the new console app project doesn't have access to the class library. 1. Try out the program by entering strings and pressing Enter, then press Enter to exit. - :::image type="content" source="media/library-with-visual-studio/run-showcase-net6.png" alt-text="Console window with ShowCase running"::: + :::image type="content" source="media/library-with-visual-studio/run-showcase.png" alt-text="Console window with ShowCase running"::: ## Additional resources @@ -130,12 +130,12 @@ In this tutorial, you created a class library. In the next tutorial, you learn h > [!div class="nextstepaction"] > [Unit test a .NET class library using Visual Studio](testing-library-with-visual-studio.md) -Or you can skip automated unit testing and learn how to share the library by creating a NuGet package: +Or, you can skip automated unit testing and learn how to share the library by creating a NuGet package: > [!div class="nextstepaction"] > [Create and publish a package using Visual Studio](/nuget/quickstart/create-and-publish-a-package-using-visual-studio) -Or learn how to publish a console app. If you publish the console app from the solution you created in this tutorial, the class library goes with it as a *.dll* file. +Or, learn how to publish a console app. If you publish the console app from the solution you created in this tutorial, the class library goes with it as a *.dll* file. > [!div class="nextstepaction"] > [Publish a .NET console application using Visual Studio](publishing-with-visual-studio.md) diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-hit-net6.png b/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-hit-net6.png deleted file mode 100644 index 5f855ac978801..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-hit-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-hit.png b/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-hit.png new file mode 100644 index 0000000000000..bf460fadf8c79 Binary files /dev/null and b/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-hit.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-settings-net6.png b/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-settings-net6.png deleted file mode 100644 index 3077499682f41..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-settings-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-settings.png b/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-settings.png new file mode 100644 index 0000000000000..bcd30bcc025c4 Binary files /dev/null and b/docs/core/tutorials/media/debugging-with-visual-studio/breakpoint-settings.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/console-window.png b/docs/core/tutorials/media/debugging-with-visual-studio/console-window.png deleted file mode 100644 index cdc508d4f3b4f..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/console-window.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/immediate-window-output.png b/docs/core/tutorials/media/debugging-with-visual-studio/immediate-window-output.png index 199450f1c469d..40130542f34a9 100644 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/immediate-window-output.png and b/docs/core/tutorials/media/debugging-with-visual-studio/immediate-window-output.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/locals-immediate-window.png b/docs/core/tutorials/media/debugging-with-visual-studio/locals-immediate-window.png index b22f98f326cd7..1b4fc767a8352 100644 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/locals-immediate-window.png and b/docs/core/tutorials/media/debugging-with-visual-studio/locals-immediate-window.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/set-breakpoint-in-editor-net6.png b/docs/core/tutorials/media/debugging-with-visual-studio/set-breakpoint-in-editor-net6.png deleted file mode 100644 index 4118572a0eab3..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/set-breakpoint-in-editor-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/set-breakpoint-in-editor.png b/docs/core/tutorials/media/debugging-with-visual-studio/set-breakpoint-in-editor.png new file mode 100644 index 0000000000000..2cbe62727f96b Binary files /dev/null and b/docs/core/tutorials/media/debugging-with-visual-studio/set-breakpoint-in-editor.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/step-into-method-net6.png b/docs/core/tutorials/media/debugging-with-visual-studio/step-into-method-net6.png deleted file mode 100644 index 52e80aaba6c7a..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/step-into-method-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/step-into-method.png b/docs/core/tutorials/media/debugging-with-visual-studio/step-into-method.png new file mode 100644 index 0000000000000..981db03b960d4 Binary files /dev/null and b/docs/core/tutorials/media/debugging-with-visual-studio/step-into-method.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/step-into-source-method-net6.png b/docs/core/tutorials/media/debugging-with-visual-studio/step-into-source-method-net6.png deleted file mode 100644 index e331c0c2dd5e2..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/step-into-source-method-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/step-into-source-method.png b/docs/core/tutorials/media/debugging-with-visual-studio/step-into-source-method.png new file mode 100644 index 0000000000000..b643787a8d711 Binary files /dev/null and b/docs/core/tutorials/media/debugging-with-visual-studio/step-into-source-method.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/vb-step-into-method.png b/docs/core/tutorials/media/debugging-with-visual-studio/vb-step-into-method.png deleted file mode 100644 index b72bb55377037..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/vb-step-into-method.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/vb-step-into-source-method.png b/docs/core/tutorials/media/debugging-with-visual-studio/vb-step-into-source-method.png deleted file mode 100644 index 7b96d142919ac..0000000000000 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/vb-step-into-source-method.png and /dev/null differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-debug.png b/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-debug.png index 263ce46b13153..458b48430c69f 100644 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-debug.png and b/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-debug.png differ diff --git a/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-release.png b/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-release.png index 63a615f43a51f..6ad2732f99da1 100644 Binary files a/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-release.png and b/docs/core/tutorials/media/debugging-with-visual-studio/visual-studio-toolbar-release.png differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/add-reference-context-menu.png b/docs/core/tutorials/media/library-with-visual-studio/add-reference-context-menu.png index eba8d9eee80f4..f131d1922a716 100644 Binary files a/docs/core/tutorials/media/library-with-visual-studio/add-reference-context-menu.png and b/docs/core/tutorials/media/library-with-visual-studio/add-reference-context-menu.png differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/blank-solution.png b/docs/core/tutorials/media/library-with-visual-studio/blank-solution.png index 0d919563d2705..5e7e9cb8385ee 100644 Binary files a/docs/core/tutorials/media/library-with-visual-studio/blank-solution.png and b/docs/core/tutorials/media/library-with-visual-studio/blank-solution.png differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/manage-project-references.png b/docs/core/tutorials/media/library-with-visual-studio/manage-project-references.png index d65ad14671321..bdfc4bee57046 100644 Binary files a/docs/core/tutorials/media/library-with-visual-studio/manage-project-references.png and b/docs/core/tutorials/media/library-with-visual-studio/manage-project-references.png differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/run-showcase-net6.png b/docs/core/tutorials/media/library-with-visual-studio/run-showcase-net6.png deleted file mode 100644 index 4c7580b99a474..0000000000000 Binary files a/docs/core/tutorials/media/library-with-visual-studio/run-showcase-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/run-showcase.png b/docs/core/tutorials/media/library-with-visual-studio/run-showcase.png new file mode 100644 index 0000000000000..f888ff75b45f4 Binary files /dev/null and b/docs/core/tutorials/media/library-with-visual-studio/run-showcase.png differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/set-startup-project-context-menu.png b/docs/core/tutorials/media/library-with-visual-studio/set-startup-project-context-menu.png index ee00519e656a0..0ab6809dd5e85 100644 Binary files a/docs/core/tutorials/media/library-with-visual-studio/set-startup-project-context-menu.png and b/docs/core/tutorials/media/library-with-visual-studio/set-startup-project-context-menu.png differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/vb/library-project-properties-net8.png b/docs/core/tutorials/media/library-with-visual-studio/vb/library-project-properties-net8.png deleted file mode 100644 index 312fb0d99ad60..0000000000000 Binary files a/docs/core/tutorials/media/library-with-visual-studio/vb/library-project-properties-net8.png and /dev/null differ diff --git a/docs/core/tutorials/media/library-with-visual-studio/vb/library-project-properties.png b/docs/core/tutorials/media/library-with-visual-studio/vb/library-project-properties.png new file mode 100644 index 0000000000000..f815d6554f0f8 Binary files /dev/null and b/docs/core/tutorials/media/library-with-visual-studio/vb/library-project-properties.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/pick-publish-target.png b/docs/core/tutorials/media/publishing-with-visual-studio/pick-publish-target.png index f97d7023fb964..73124c0b026de 100644 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/pick-publish-target.png and b/docs/core/tutorials/media/publishing-with-visual-studio/pick-publish-target.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/pick-specific-publish-target.png b/docs/core/tutorials/media/publishing-with-visual-studio/pick-specific-publish-target.png index 30683ef62a4b4..c48510c3e4a02 100644 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/pick-specific-publish-target.png and b/docs/core/tutorials/media/publishing-with-visual-studio/pick-specific-publish-target.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/publish-context-menu.png b/docs/core/tutorials/media/publishing-with-visual-studio/publish-context-menu.png index 37da1ce3ae345..172bf12d0bc22 100644 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/publish-context-menu.png and b/docs/core/tutorials/media/publishing-with-visual-studio/publish-context-menu.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-loc-tab-net8.png b/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-loc-tab-net8.png deleted file mode 100644 index 63e11e16647dc..0000000000000 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-loc-tab-net8.png and /dev/null differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-loc-tab.png b/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-loc-tab.png new file mode 100644 index 0000000000000..4607ce2436f89 Binary files /dev/null and b/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-loc-tab.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-net8.png b/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-net8.png deleted file mode 100644 index 8463f55f6fe04..0000000000000 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/publish-page-net8.png and /dev/null differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/publish-page.png b/docs/core/tutorials/media/publishing-with-visual-studio/publish-page.png new file mode 100644 index 0000000000000..609e32432e1e4 Binary files /dev/null and b/docs/core/tutorials/media/publishing-with-visual-studio/publish-page.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/published-files-output-net8.png b/docs/core/tutorials/media/publishing-with-visual-studio/published-files-output-net8.png deleted file mode 100644 index 9f03c6fbf662d..0000000000000 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/published-files-output-net8.png and /dev/null differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/published-files-output.png b/docs/core/tutorials/media/publishing-with-visual-studio/published-files-output.png new file mode 100644 index 0000000000000..7c1bcdc10d7cc Binary files /dev/null and b/docs/core/tutorials/media/publishing-with-visual-studio/published-files-output.png differ diff --git a/docs/core/tutorials/media/publishing-with-visual-studio/visual-studio-toolbar-release.png b/docs/core/tutorials/media/publishing-with-visual-studio/visual-studio-toolbar-release.png index 63a615f43a51f..12b96908464c4 100644 Binary files a/docs/core/tutorials/media/publishing-with-visual-studio/visual-studio-toolbar-release.png and b/docs/core/tutorials/media/publishing-with-visual-studio/visual-studio-toolbar-release.png differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/add-project-reference-string-library-test.png b/docs/core/tutorials/media/testing-library-with-visual-studio/add-project-reference-string-library-test.png new file mode 100644 index 0000000000000..6bc29af06a1d8 Binary files /dev/null and b/docs/core/tutorials/media/testing-library-with-visual-studio/add-project-reference-string-library-test.png differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/additional-information-mstest.png b/docs/core/tutorials/media/testing-library-with-visual-studio/additional-information-mstest.png new file mode 100644 index 0000000000000..0145bde9b1b0c Binary files /dev/null and b/docs/core/tutorials/media/testing-library-with-visual-studio/additional-information-mstest.png differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/advanced-save-options.png b/docs/core/tutorials/media/testing-library-with-visual-studio/advanced-save-options.png deleted file mode 100644 index dbd63fe289044..0000000000000 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/advanced-save-options.png and /dev/null differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/build-library-context-menu.png b/docs/core/tutorials/media/testing-library-with-visual-studio/build-library-context-menu.png deleted file mode 100644 index 29ed20e1b3fb9..0000000000000 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/build-library-context-menu.png and /dev/null differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-detail.png b/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-detail.png index d981ae809a80e..2fb403aab4d50 100644 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-detail.png and b/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-detail.png differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-window.png b/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-window.png index 2b809d6cdc7da..55c893b012886 100644 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-window.png and b/docs/core/tutorials/media/testing-library-with-visual-studio/failed-test-window.png differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/save-file-as-dialog.png b/docs/core/tutorials/media/testing-library-with-visual-studio/save-file-as-dialog.png deleted file mode 100644 index 264f9aa17acde..0000000000000 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/save-file-as-dialog.png and /dev/null differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/test-explorer-window.png b/docs/core/tutorials/media/testing-library-with-visual-studio/test-explorer-window.png index 5fb542194c131..32f3f8c6079ee 100644 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/test-explorer-window.png and b/docs/core/tutorials/media/testing-library-with-visual-studio/test-explorer-window.png differ diff --git a/docs/core/tutorials/media/testing-library-with-visual-studio/visual-studio-toolbar-release.png b/docs/core/tutorials/media/testing-library-with-visual-studio/visual-studio-toolbar-release.png deleted file mode 100644 index f7a926fd44895..0000000000000 Binary files a/docs/core/tutorials/media/testing-library-with-visual-studio/visual-studio-toolbar-release.png and /dev/null differ diff --git a/docs/core/tutorials/media/with-visual-studio/configure-new-project.png b/docs/core/tutorials/media/with-visual-studio/configure-new-project.png index 8fa5f6122c3b3..b59cd8b9e0f76 100644 Binary files a/docs/core/tutorials/media/with-visual-studio/configure-new-project.png and b/docs/core/tutorials/media/with-visual-studio/configure-new-project.png differ diff --git a/docs/core/tutorials/media/with-visual-studio/create-new-project.png b/docs/core/tutorials/media/with-visual-studio/create-new-project.png index 840627a3a1187..8fe6360e754eb 100644 Binary files a/docs/core/tutorials/media/with-visual-studio/create-new-project.png and b/docs/core/tutorials/media/with-visual-studio/create-new-project.png differ diff --git a/docs/core/tutorials/media/with-visual-studio/hello-world-console-net6.png b/docs/core/tutorials/media/with-visual-studio/hello-world-console-net6.png deleted file mode 100644 index aacf8119b89c8..0000000000000 Binary files a/docs/core/tutorials/media/with-visual-studio/hello-world-console-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/with-visual-studio/hello-world-update-net6.png b/docs/core/tutorials/media/with-visual-studio/hello-world-update-net6.png deleted file mode 100644 index 2517577b1da91..0000000000000 Binary files a/docs/core/tutorials/media/with-visual-studio/hello-world-update-net6.png and /dev/null differ diff --git a/docs/core/tutorials/media/with-visual-studio/hello-world-update.png b/docs/core/tutorials/media/with-visual-studio/hello-world-update.png new file mode 100644 index 0000000000000..d489ed3df11c3 Binary files /dev/null and b/docs/core/tutorials/media/with-visual-studio/hello-world-update.png differ diff --git a/docs/core/tutorials/media/with-visual-studio/start-window-2022.png b/docs/core/tutorials/media/with-visual-studio/start-window-2022.png deleted file mode 100644 index 68839c7d2cdb6..0000000000000 Binary files a/docs/core/tutorials/media/with-visual-studio/start-window-2022.png and /dev/null differ diff --git a/docs/core/tutorials/media/with-visual-studio/start-window.png b/docs/core/tutorials/media/with-visual-studio/start-window.png new file mode 100644 index 0000000000000..2b5fc838c58c8 Binary files /dev/null and b/docs/core/tutorials/media/with-visual-studio/start-window.png differ diff --git a/docs/core/tutorials/publishing-with-visual-studio.md b/docs/core/tutorials/publishing-with-visual-studio.md index 2bccb7fcce0e6..03c9f4128c941 100644 --- a/docs/core/tutorials/publishing-with-visual-studio.md +++ b/docs/core/tutorials/publishing-with-visual-studio.md @@ -1,7 +1,7 @@ --- title: Publish a .NET console application using Visual Studio description: Learn how to use Visual Studio to create the set of files that are needed to run a .NET application. -ms.date: 10/23/2025 +ms.date: 01/14/2026 ai-usage: ai-assisted ms.custom: - "vs-dotnet" @@ -39,13 +39,13 @@ This tutorial works with the console app that you create in [Create a .NET conso 1. On the **Location** tab of the **Publish** page, select **Finish**. - :::image type="content" source="media/publishing-with-visual-studio/publish-page-loc-tab-net8.png" alt-text="Visual Studio Publish page Location tab"::: + :::image type="content" source="media/publishing-with-visual-studio/publish-page-loc-tab.png" alt-text="Visual Studio Publish page Location tab"::: 1. On the **Publish profile creation progress** page, select **Close**. 1. On the **Publish** tab of the **Publish** window, select **Publish**. - :::image type="content" source="media/publishing-with-visual-studio/publish-page-net8.png" alt-text="Visual Studio Publish window"::: + :::image type="content" source="media/publishing-with-visual-studio/publish-page.png" alt-text="Visual Studio Publish window"::: ## Inspect the files @@ -55,9 +55,9 @@ In the following steps, you'll look at the files created by the publish process. 1. In **Solution Explorer**, select **Show all files**. -1. In the project folder, expand *bin/Release/{net}/publish*. (Where {net} is the target framework folder, such as _net8.0_.) +1. In the project folder, expand *bin/Release/{net}/publish*. (Where {net} is the target framework folder, such as _net10.0_.) - :::image type="content" source="media/publishing-with-visual-studio/published-files-output-net8.png" alt-text="Solution Explorer showing published files"::: + :::image type="content" source="media/publishing-with-visual-studio/published-files-output.png" alt-text="Solution Explorer showing published files"::: As the image shows, the published output includes the following files: @@ -88,7 +88,7 @@ In the following steps, you'll look at the files created by the publish process. 1. Open a command prompt and navigate to the *publish* folder. To do that, enter `cd` and then paste the full path. For example: ```console - cd C:\Projects\HelloWorld\bin\Release\net8.0\publish\ + cd C:\Projects\HelloWorld\bin\Release\net10.0\publish\ ``` 1. Run the app by using the executable: diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/ShowCase/ShowCase.csproj b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/ShowCase/ShowCase.csproj index 6d76f46f0f5da..617041f7d4c21 100644 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/ShowCase/ShowCase.csproj +++ b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/ShowCase/ShowCase.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibrary/StringLibrary.csproj b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibrary/StringLibrary.csproj index 8d2b2325b0b6c..b2c1cc7168cf6 100644 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibrary/StringLibrary.csproj +++ b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibrary/StringLibrary.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/MSTestSettings.cs b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/MSTestSettings.cs new file mode 100644 index 0000000000000..aaf278c844f03 --- /dev/null +++ b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj index 59d7e713f336b..6ecde6614127c 100644 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj +++ b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/StringLibraryTest.csproj @@ -1,21 +1,24 @@ - + - net8.0 + net10.0 + latest + enable enable - false + true + Exe - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + + diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/Test1.cs b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/Test1.cs new file mode 100644 index 0000000000000..641df1b18285e --- /dev/null +++ b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/Test1.cs @@ -0,0 +1,45 @@ +using UtilityLibraries; + +namespace StringLibraryTest +{ + [TestClass] + public sealed class Test1 + { + [TestMethod] + public void TestStartsWithUpper() + { + // Tests that we expect to return true. + string[] words = ["Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"]; + foreach (var word in words) + { + bool result = word.StartsWithUpper(); + Assert.IsTrue(result, $"Expected for '{word}': true; Actual: {result}"); + } + } + + [TestMethod] + public void TestDoesNotStartWithUpper() + { + // Tests that we expect to return false. + string[] words = ["alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство", + "1234", ".", ";", " "]; + foreach (var word in words) + { + bool result = word.StartsWithUpper(); + Assert.IsFalse(result, $"Expected for '{word}': false; Actual: {result}"); + } + } + + [TestMethod] + public void DirectCallWithNullOrEmpty() + { + // Tests that we expect to return false. + string?[] words = [string.Empty, null]; + foreach (var word in words) + { + bool result = StringLibrary.StartsWithUpper(word); + Assert.IsFalse(result, $"Expected for '{word ?? ""}': false; Actual: {result}"); + } + } + } +} diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/UnitTest1.cs b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/UnitTest1.cs deleted file mode 100644 index 81fb526c258d3..0000000000000 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTest/UnitTest1.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using UtilityLibraries; - -namespace StringLibraryTest; - -[TestClass] -public class UnitTest1 -{ - [TestMethod] - public void TestStartsWithUpper() - { - // Tests that we expect to return true. - string[] words = ["Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"]; - foreach (var word in words) - { - bool result = word.StartsWithUpper(); - Assert.IsTrue(result, $"Expected for '{word}': true; Actual: {result}"); - } - } - - [TestMethod] - public void TestDoesNotStartWithUpper() - { - // Tests that we expect to return false. - string[] words = ["alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство", - "1234", ".", ";", " "]; - foreach (var word in words) - { - bool result = word.StartsWithUpper(); - Assert.IsFalse(result, $"Expected for '{word}': false; Actual: {result}"); - } - } - - [TestMethod] - public void DirectCallWithNullOrEmpty() - { - // Tests that we expect to return false. - string?[] words = [string.Empty, null]; - foreach (var word in words) - { - bool result = StringLibrary.StartsWithUpper(word); - Assert.IsFalse(result, $"Expected for '{word ?? ""}': false; Actual: {result}"); - } - } -} diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/GlobalUsings.cs b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/GlobalUsings.cs deleted file mode 100644 index 974ab1211e396..0000000000000 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/StringLibraryTest.csproj b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/StringLibraryTest.csproj deleted file mode 100644 index 4fe3dfcd83bde..0000000000000 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/StringLibraryTest.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net8.0 - enable - enable - - false - true - - - - - - - - - - - - - - diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/UnitTest1.cs b/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/UnitTest1.cs deleted file mode 100644 index 3a1e800acd120..0000000000000 --- a/docs/core/tutorials/snippets/library-with-visual-studio/csharp/StringLibraryTestNet8/UnitTest1.cs +++ /dev/null @@ -1,44 +0,0 @@ -using UtilityLibraries; - -namespace StringLibraryTest; - -[TestClass] -public class UnitTest1 -{ - [TestMethod] - public void TestStartsWithUpper() - { - // Tests that we expect to return true. - string[] words = ["Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"]; - foreach (var word in words) - { - bool result = word.StartsWithUpper(); - Assert.IsTrue(result, $"Expected for '{word}': true; Actual: {result}"); - } - } - - [TestMethod] - public void TestDoesNotStartWithUpper() - { - // Tests that we expect to return false. - string[] words = ["alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство", - "1234", ".", ";", " "]; - foreach (var word in words) - { - bool result = word.StartsWithUpper(); - Assert.IsFalse(result, $"Expected for '{word}': false; Actual: {result}"); - } - } - - [TestMethod] - public void DirectCallWithNullOrEmpty() - { - // Tests that we expect to return false. - string?[] words = [string.Empty, null]; - foreach (var word in words) - { - bool result = StringLibrary.StartsWithUpper(word); - Assert.IsFalse(result, $"Expected for '{word ?? ""}': false; Actual: {result}"); - } - } -} diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/vb/ShowCase/ShowCase.vbproj b/docs/core/tutorials/snippets/library-with-visual-studio/vb/ShowCase/ShowCase.vbproj index e273a8c59238a..96c996e002428 100644 --- a/docs/core/tutorials/snippets/library-with-visual-studio/vb/ShowCase/ShowCase.vbproj +++ b/docs/core/tutorials/snippets/library-with-visual-studio/vb/ShowCase/ShowCase.vbproj @@ -3,7 +3,7 @@ Exe ShowCase - net8.0 + net10.0 diff --git a/docs/core/tutorials/snippets/library-with-visual-studio/vb/StringLibraryTest/StringLibraryTest.vbproj b/docs/core/tutorials/snippets/library-with-visual-studio/vb/StringLibraryTest/StringLibraryTest.vbproj index 8d6b5b2789e28..77a91788ca77f 100644 --- a/docs/core/tutorials/snippets/library-with-visual-studio/vb/StringLibraryTest/StringLibraryTest.vbproj +++ b/docs/core/tutorials/snippets/library-with-visual-studio/vb/StringLibraryTest/StringLibraryTest.vbproj @@ -2,7 +2,7 @@ StringLibraryTest - net8.0 + net10.0 false diff --git a/docs/core/tutorials/snippets/with-visual-studio/csharp/HelloWorld.csproj b/docs/core/tutorials/snippets/with-visual-studio/csharp/HelloWorld.csproj index f704bf4988fa6..0ece068f6df1a 100644 --- a/docs/core/tutorials/snippets/with-visual-studio/csharp/HelloWorld.csproj +++ b/docs/core/tutorials/snippets/with-visual-studio/csharp/HelloWorld.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable enable diff --git a/docs/core/tutorials/snippets/with-visual-studio/vb/HelloWorld.vbproj b/docs/core/tutorials/snippets/with-visual-studio/vb/HelloWorld.vbproj index a114aa59790a0..ea29404a0128c 100644 --- a/docs/core/tutorials/snippets/with-visual-studio/vb/HelloWorld.vbproj +++ b/docs/core/tutorials/snippets/with-visual-studio/vb/HelloWorld.vbproj @@ -3,7 +3,7 @@ Exe vb_with_visual_studio - net8.0 + net10.0 diff --git a/docs/core/tutorials/testing-library-with-visual-studio-code.md b/docs/core/tutorials/testing-library-with-visual-studio-code.md index 17774e3993743..11dd5467810ed 100644 --- a/docs/core/tutorials/testing-library-with-visual-studio-code.md +++ b/docs/core/tutorials/testing-library-with-visual-studio-code.md @@ -80,7 +80,7 @@ To create the test methods: 1. Open *StringLibraryTest/UnitTest1.cs* and replace all of the code with the following code. - :::code language="csharp" source="./snippets/library-with-visual-studio/csharp/StringLibraryTest/UnitTest1.cs"::: + :::code language="csharp" source="./snippets/library-with-visual-studio/csharp/StringLibraryTest/Test1.cs"::: The test of uppercase characters in the `TestStartsWithUpper` method includes the Greek capital letter alpha (U+0391) and the Cyrillic capital letter EM (U+041C). The test of lowercase characters in the `TestDoesNotStartWithUpper` method includes the Greek small letter alpha (U+03B1) and the Cyrillic small letter Ghe (U+0433). diff --git a/docs/core/tutorials/testing-library-with-visual-studio.md b/docs/core/tutorials/testing-library-with-visual-studio.md index 03d09c6e1b367..716a2ba3f7258 100644 --- a/docs/core/tutorials/testing-library-with-visual-studio.md +++ b/docs/core/tutorials/testing-library-with-visual-studio.md @@ -1,7 +1,7 @@ --- title: Test a .NET class library using Visual Studio description: Learn how to use Visual Studio to create and run a unit test project for a .NET class library. -ms.date: 10/23/2025 +ms.date: 01/14/2026 ai-usage: ai-assisted dev_langs: - "csharp" @@ -34,19 +34,23 @@ Unit tests provide automated software testing during your development and publis 1. On the **Configure your new project** page, enter **StringLibraryTest** in the **Project name** box. Then choose **Next**. - 1. On the **Additional information** page, select **.NET 8** in the **Framework** box. Then choose **Create**. + 1. On the **Additional information** page, select **.NET 10** in the **Framework** box, select **Microsoft.Testing.Platform** for the **Test runner**, and then choose **Create**. + + :::image type="content" source="./media/testing-library-with-visual-studio/additional-information-mstest.png" alt-text="Enter additional information for the MSTest Test Project"::: 1. Visual Studio creates the project and opens the class file in the code window with the following code. If the language you want to use isn't shown, change the language selector at the top of the page. ```csharp - namespace StringLibraryTest; - - [TestClass] - public class UnitTest1 + namespace StringLibraryTest { - [TestMethod] - public void TestMethod1() + + [TestClass] + public sealed class Test1 { + [TestMethod] + public void TestMethod1() + { + } } } ``` @@ -56,7 +60,7 @@ Unit tests provide automated software testing during your development and publis Namespace StringLibraryTest - Public Class UnitTest1 + Public Class Test1 Sub TestSub() @@ -67,19 +71,21 @@ Unit tests provide automated software testing during your development and publis The source code created by the unit test template does the following: - - Imports the namespace, which contains the types used for unit testing. In C#, the namespace is imported via a `global using` directive in *GlobalUsings.cs*. - - Applies the attribute to the `UnitTest1` class. + - Includes in the StringLibraryTest project file in C#, and imports in Visual Basic. + - Applies the attribute to the `Test1` class. - Applies the attribute to define `TestMethod1` in C# or `TestSub` in Visual Basic. Each method tagged with [[TestMethod]](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute) in a test class tagged with [[TestClass]](xref:Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute) executes automatically when the unit test runs. ## Add a project reference -For the test project to work with the `StringLibrary` class, add a reference in the **StringLibraryTest** project to the `StringLibrary` project. +For the test project to work with the `StringLibrary` class, add a reference in the **StringLibraryTest** project to the `StringLibrary` project. Adding a reference to the `StringLibrary` assembly lets the compiler find **StringLibrary** methods while compiling the **StringLibraryTest** project. 1. In **Solution Explorer**, right-click the **Dependencies** node of the **StringLibraryTest** project and select **Add Project Reference** from the context menu. -1. In the **Reference Manager** dialog, expand the **Projects** node, and select the box next to **StringLibrary**. Adding a reference to the `StringLibrary` assembly lets the compiler find **StringLibrary** methods while compiling the **StringLibraryTest** project. +1. In the **Reference Manager** dialog, select the box next to **StringLibrary**. + + :::image type="content" source="./media/testing-library-with-visual-studio/add-project-reference-string-library-test.png" alt-text="Add StringLibrary as a project reference for StringLibraryTest."::: 1. Select **OK**. @@ -106,23 +112,19 @@ Define three methods, each of which calls an **Save UnitTest1.cs As** or **File** > **Save UnitTest1.vb As**. In the **Save File As** dialog, select the arrow beside the **Save** button, and select **Save with Encoding**. - - :::image type="content" source="./media/testing-library-with-visual-studio/save-file-as-dialog.png" alt-text="Visual Studio Save File As dialog"::: +1. On the menu bar, select **File** > **Save Test1.cs As** or **File** > **Save Test1.vb As**. In the **Save File As** dialog, select the arrow beside the **Save** button, and select **Save with Encoding**. 1. In the **Confirm Save As** dialog, select the **Yes** button to save the file. 1. In the **Advanced Save Options** dialog, select **Unicode (UTF-8 with signature) - Codepage 65001** from the **Encoding** drop-down list and select **OK**. - :::image type="content" source="./media/testing-library-with-visual-studio/advanced-save-options.png" alt-text="Visual Studio Advanced Save Options dialog"::: - If you fail to save your source code as a UTF8-encoded file, Visual Studio might save it as an ASCII file. When that happens, the runtime doesn't accurately decode the UTF8 characters outside of the ASCII range, and the test results aren't correct. 1. On the menu bar, select **Test** > **Run All Tests**. If the **Test Explorer** window doesn't open, open it by choosing **Test** > **Test Explorer**. The three tests are listed in the **Passed Tests** section, and the **Summary** section reports the result of the test run. @@ -166,12 +168,8 @@ To test the Release build: 1. In the Visual Studio toolbar, change the build configuration from **Debug** to **Release**. - :::image type="content" source="./media/testing-library-with-visual-studio/visual-studio-toolbar-release.png" alt-text="Visual Studio toolbar with release build highlighted"::: - 1. In **Solution Explorer**, right-click the **StringLibrary** project and select **Build** from the context menu to recompile the library. - :::image type="content" source="./media/testing-library-with-visual-studio/build-library-context-menu.png" alt-text="StringLibrary context menu with build command"::: - 1. Run the unit tests by choosing **Test** > **Run All Tests** from the menu bar. The tests pass. ## Debug tests diff --git a/docs/core/tutorials/with-visual-studio.md b/docs/core/tutorials/with-visual-studio.md index 328af810710cf..7066e8a5b9738 100644 --- a/docs/core/tutorials/with-visual-studio.md +++ b/docs/core/tutorials/with-visual-studio.md @@ -1,7 +1,7 @@ --- title: Create a .NET console application using Visual Studio description: Learn how to create a .NET console application with C# or Visual Basic using Visual Studio. -ms.date: 11/22/2024 +ms.date: 01/13/2026 dev_langs: - "csharp" - "vb" @@ -9,11 +9,11 @@ ms.custom: vs-dotnet --- # Tutorial: Create a .NET console application using Visual Studio -This tutorial shows how to create and run a .NET console application in Visual Studio 2022. +This tutorial shows how to create and run a .NET console application in Visual Studio 2026. ## Prerequisites -- [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link) with the **.NET desktop development** workload installed. The .NET SDK is automatically installed when you select this workload. +- [Visual Studio 2026 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link) with the **.NET desktop development** workload installed. The .NET SDK is automatically installed when you select this workload. For more information, see [Install the .NET SDK with Visual Studio](../install/windows.md#install-with-visual-studio). @@ -25,7 +25,7 @@ Create a .NET console app project named "HelloWorld". 1. On the start page, choose **Create a new project**. - :::image type="content" source="./media/with-visual-studio/start-window-2022.png" alt-text="Create a new project button selected on the Visual Studio start page"::: + :::image type="content" source="./media/with-visual-studio/start-window.png" alt-text="Create a new project button selected on the Visual Studio start page"::: 1. On the **Create a new project** page, enter **console** in the search box. Next, choose **C#** or **Visual Basic** from the language list, and then choose **All platforms** from the platform list. Choose the **Console App** template, and then choose **Next**. @@ -39,7 +39,7 @@ Create a .NET console app project named "HelloWorld". :::image type="content" source="./media/with-visual-studio/configure-new-project.png" alt-text="Configure your new project window with Project name, location, and solution name fields"::: 1. In the **Additional information** dialog: - - Select **.NET 8**. + - Select **.NET 10**. - Select **Do not use top-level statements**. - Select **Create**. @@ -79,8 +79,6 @@ Create a .NET console app project named "HelloWorld". A console window opens with the text "Hello, World!" printed on the screen. (Or "Hello World!" without a comma in the Visual Basic project template.) - :::image type="content" source="./media/with-visual-studio/hello-world-console-net6.png" alt-text="Console window showing Hello World Press any key to continue"::: - 1. Press any key to close the console window. ## Enhance the app @@ -102,7 +100,7 @@ Enhance the application to prompt the user for their name and display it along w 1. Respond to the prompt by entering a name and pressing the Enter key. - :::image type="content" source="./media/with-visual-studio/hello-world-update-net6.png" alt-text="Console window with modified program output"::: + :::image type="content" source="./media/with-visual-studio/hello-world-update.png" alt-text="Console window with modified program output"::: 1. Press any key to close the console window. diff --git a/docs/core/versions/selection.md b/docs/core/versions/selection.md index d71bd791ce758..4bc88331bc2bd 100644 --- a/docs/core/versions/selection.md +++ b/docs/core/versions/selection.md @@ -148,7 +148,7 @@ The roll-forward behavior for an application can be configured in four different ### Precedence -Roll forward behavior is set by the following order when your app is run, higher numbered items taking precedence over lower numbered items: +Roll-forward behavior is set in the following order when your app is run, with higher numbered items taking precedence over lower numbered items: 01. First the `*.runtimeconfig.json` config file is evaluated. 01. Next, the `DOTNET_ROLL_FORWARD` environment variable is considered, overriding the previous check. diff --git a/docs/csharp/advanced-topics/reflection-and-attributes/index.md b/docs/csharp/advanced-topics/reflection-and-attributes/index.md index 06958d4c026ae..3990903ab502a 100644 --- a/docs/csharp/advanced-topics/reflection-and-attributes/index.md +++ b/docs/csharp/advanced-topics/reflection-and-attributes/index.md @@ -16,7 +16,7 @@ Attributes have the following properties: ## Work with reflection -[Reflection](../../../fundamentals/reflection/reflection.md) APIs provided by describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. When you use attributes in your code, reflection enables you to access them. For more information, see [Attributes](../../../standard/attributes/index.md). +[Reflection](../../../fundamentals/reflection/overview.md) APIs provided by describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. When you use attributes in your code, reflection enables you to access them. For more information, see [Attributes](../../../standard/attributes/index.md). Here's a simple example of reflection with the method. All types from the `Object` base class inherit this method, which is used to obtain the type of a variable: @@ -187,7 +187,7 @@ Reflection is useful in the following scenarios: - [Common attributes (C#)](../../language-reference/attributes/global.md) - [Caller information (C#)](../../language-reference/attributes/caller-information.md) - [Attributes](../../../standard/attributes/index.md) -- [Reflection](../../../fundamentals/reflection/reflection.md) +- [Reflection](../../../fundamentals/reflection/overview.md) - [View type information](../../../fundamentals/reflection/viewing-type-information.md) - [Reflection and generic types](../../../fundamentals/reflection/reflection-and-generic-types.md) - diff --git a/docs/csharp/fundamentals/program-structure/main-command-line.md b/docs/csharp/fundamentals/program-structure/main-command-line.md index cff65bf66216b..08e82eaa09cd5 100644 --- a/docs/csharp/fundamentals/program-structure/main-command-line.md +++ b/docs/csharp/fundamentals/program-structure/main-command-line.md @@ -181,7 +181,7 @@ long num = Convert.ToInt64(s); For more information, see and . > [!TIP] -> Parsing command-line arguments can be complex. Consider using the [System.CommandLine](../../../standard/commandline/index.md) library (currently in beta) to simplify the process. +> Parsing command-line arguments can be complex. Consider using the [System.CommandLine](../../../standard/commandline/index.md) library to simplify the process. The following example shows how to use command-line arguments in a console application. The application takes one argument at run time, converts the argument to an integer, and calculates the factorial of the number. If no arguments are supplied, the application issues a message that explains the correct usage of the program. diff --git a/docs/csharp/fundamentals/program-structure/top-level-statements.md b/docs/csharp/fundamentals/program-structure/top-level-statements.md index 743c695a5301e..f79dad8c10a60 100644 --- a/docs/csharp/fundamentals/program-structure/top-level-statements.md +++ b/docs/csharp/fundamentals/program-structure/top-level-statements.md @@ -1,7 +1,7 @@ --- title: "Top-level statements - programs without Main methods" description: Learn about top-level statements. You can create programs without the ceremony of a Program class and a Main method. -ms.date: 06/23/2025 +ms.date: 01/12/2026 helpviewer_keywords: - "C# language, top-level statements" - "C# language, Main method" @@ -34,7 +34,7 @@ A project can have any number of source code files that don't have top-level sta ## No other entry points -You can write a `Main` method explicitly, but it can't function as an entry point. The compiler issues the following warning: +You can explicitly write a `Main` method, but it can't function as an entry point. The compiler issues the following warning: > CS7022 The entry point of the program is global code; ignoring 'Main()' entry point. @@ -42,7 +42,7 @@ In a project with top-level statements, you can't use the [-main](../../language ## `using` directives -For the single file containing top-level statements `using` directives must come first in that file, as in this example: +For the single file containing top-level statements, `using` directives must come first in that file, as in this example: :::code language="csharp" source="snippets/top-level-statements-1/Program.cs"::: @@ -64,7 +64,7 @@ Top-level statements can reference the `args` variable to access any command-lin ## `await` -You can call an async method by using `await`. For example: +Use `await` to call an async method. For example: :::code language="csharp" source="snippets/top-level-statements-4/Program.cs"::: @@ -76,7 +76,7 @@ To return an `int` value when the application ends, use the `return` statement a ## Implicit entry point method -The compiler generates a method to serve as the program entry point for a project with top-level statements. The signature of the method depends on whether the top-level statements contain the `await` keyword or the `return` statement. The following table shows what the method signature would look like, using the method name `Main` in the table for convenience. +The compiler generates a method to serve as the program entry point for a project with top-level statements. The signature of the method depends on whether the top-level statements contain the `await` keyword or the `return` statement. The following table shows what the method signature looks like, using the method name `Main` in the table for convenience. | Top-level code contains | Implicit `Main` signature | |-------------------------|----------------------------------------------| @@ -85,7 +85,7 @@ The compiler generates a method to serve as the program entry point for a projec | `return` | `static int Main(string[] args)` | | No `await` or `return` | `static void Main(string[] args)` | -Beginning with C# 14, programs can be [*file-based apps*](./index.md#building-and-running-c-programs), where a single file contains the program. You run *file-based apps* with the command `dotnet run `, or using the `#!/usr/local/share/dotnet/dotnet run` directive as the first line (unix shells only). +Starting with C# 14, programs can be [*file-based apps*](./index.md#building-and-running-c-programs), where a single file contains the program. You run *file-based apps* by using the command `dotnet `, or by using the `#!/usr/bin/env dotnet` directive as the first line (Unix shells only). ## C# language specification diff --git a/docs/csharp/fundamentals/tutorials/file-based-programs.md b/docs/csharp/fundamentals/tutorials/file-based-programs.md index 582e2f174e5d0..ba3462eeba7fc 100644 --- a/docs/csharp/fundamentals/tutorials/file-based-programs.md +++ b/docs/csharp/fundamentals/tutorials/file-based-programs.md @@ -1,7 +1,7 @@ --- title: Build file-based apps description: File-based apps are command line utilities that are built and execute without a project file. The build and run commands are implicit. New syntax supports project settings in source. -ms.date: 12/12/2025 +ms.date: 01/12/2026 ms.topic: tutorial ai-usage: ai-assisted #customer intent: As a developer, I want to build utilities so that more work is automated. @@ -42,10 +42,10 @@ You build a file-based program that writes text as ASCII art. The app is contain 1. Save the file. Then, open the integrated terminal in Visual Studio Code and type: ```dotnetcli - dotnet run AsciiArt.cs + dotnet AsciiArt.cs ``` -The first time you run this program, the `dotnet` host builds the executable from your source file, stores build artifacts in a temporary folder, and then runs the created executable. You can verify this experience by typing `dotnet run AsciiArt.cs` again. This time, the `dotnet` host determines that the executable is current and runs the executable without building it again. You don't see any build output. +The first time you run this program, the `dotnet` host builds the executable from your source file, stores build artifacts in a temporary folder, and then runs the created executable. You can verify this experience by typing `dotnet AsciiArt.cs` again. This time, the `dotnet` host determines that the executable is current and runs the executable without building it again. You don't see any build output. The preceding steps demonstrate that file-based apps aren't script files. They're C# source files that the `dotnet` host builds by using a generated project file in a temporary folder. One of the lines of output displayed when you build the program should look something like this (on Windows): @@ -67,9 +67,9 @@ File-based apps are regular C# programs. The only limitation is that you must wr > [!NOTE] > -> Support for `#!` directives applies on Unix platforms only. There's no similar directive for Windows to directly execute a C# program. On Windows, you must use `dotnet run` on the command line. +> Support for `#!` directives applies on Unix platforms only. There's no similar directive for Windows to directly execute a C# program. On Windows, you must use `dotnet` on the command line. -On Unix, you can run file-based apps directly. Instead of using `dotnet run`, you type the source file name on the command line. You need to make two changes: +On Unix, run file-based apps directly by typing just the source file name. Instead of using `dotnet AsciiArt.cs`, type the source file name on the command line. You need to make two changes: 1. Set *execute* permissions on the source file: @@ -80,7 +80,7 @@ On Unix, you can run file-based apps directly. Instead of using `dotnet run`, yo 1. Add a shebang (`#!`) directive as the first line of the `AsciiArt.cs` file: ```csharp - #!/usr/local/share/dotnet/dotnet run + #!/usr/local/share/dotnet/dotnet ``` The location of `dotnet` can be different on different Unix installations. Use the command `which dotnet` to locate the `dotnet` host in your environment. @@ -116,7 +116,7 @@ Now, write all arguments on the command line to the output. 1. You can run this version by typing the following command: ```dotnetcli - dotnet run AsciiArt.cs -- This is the command line. + dotnet AsciiArt.cs -- This is the command line. ``` The `--` option indicates that all following command arguments should be passed to the AsciiArt program. The arguments `This is the command line.` are passed as an array of strings, where each string is one word: `This`, `is`, `the`, `command`, and `line.`. @@ -156,13 +156,13 @@ The preceding code handles command line arguments correctly. Now, add the code t By using bash: ```bash - cat input.txt | dotnet run AsciiArt.cs + cat input.txt | dotnet AsciiArt.cs ``` Or, by using PowerShell: ```powershell - Get-Content input.txt | dotnet run AsciiArt.cs + Get-Content input.txt | dotnet AsciiArt.cs ``` Now your program can accept either command line arguments or standard input. diff --git a/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt b/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt index 1467798177dff..18e47ad080b82 100755 --- a/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt +++ b/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt @@ -1,4 +1,4 @@ -#!/usr/local/share/dotnet/dotnet run +#!/usr/bin/env dotnet #:package Colorful.Console@1.2.15 #:package System.CommandLine@2.0.0 diff --git a/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt.cs b/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt.cs index 8b23a043b7165..97d898ffbf8d6 100755 --- a/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt.cs +++ b/docs/csharp/fundamentals/tutorials/snippets/file-based-programs/AsciiArt.cs @@ -1,4 +1,4 @@ -#!/usr/bin/env dotnet run +#!/usr/bin/env dotnet // #:package Colorful.Console@1.2.15 diff --git a/docs/csharp/language-reference/attributes/caller-information.md b/docs/csharp/language-reference/attributes/caller-information.md index 3d5f13a3ac509..faa3fdad444c2 100644 --- a/docs/csharp/language-reference/attributes/caller-information.md +++ b/docs/csharp/language-reference/attributes/caller-information.md @@ -1,54 +1,58 @@ --- title: "Attributes interpreted by the compiler: Tracking caller information" -ms.date: 11/18/2025 +ms.date: 01/14/2026 description: These attributes instruct the compiler to generate information about the code that calls a member. You use the CallerFilePath, CallerLineNumber, CallerMemberName, and CallerArgumentExpression to provide detailed trace information --- -# Determine caller information using attributes interpreted by the C# compiler +# Determine caller information by using attributes that the C# compiler interprets -Using info attributes, you obtain information about the caller to a method. You obtain the file path of the source code, the line number in the source code, and the member name of the caller. To obtain member caller information, you use attributes that are applied to optional parameters. Each optional parameter specifies a default value. The following table lists the Caller Info attributes that are defined in the namespace: +By using info attributes, you can get information about the caller to a method. You can get the file path of the source code, the line number in the source code, and the member name of the caller. To get member caller information, use attributes that you apply to optional parameters. Each optional parameter specifies a default value. -|Attribute|Description|Type| -|---|---|---| -||Full path of the source file that contains the caller. The full path is the path at compile time.|`String`| -||Line number in the source file from which the method is called.|`Integer`| -||Method name or property name of the caller.|`String`| -| |String representation of the argument expression.|`String`| +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +The following table lists the Caller Info attributes that are defined in the namespace: + +| Attribute | Description | Type | +|-----------|--------------------------------------------------------------|---| +| | Full path of the source file that contains the caller. The full path is the path at compile time. | `String` | +| | Line number in the source file from which the method is called. | `Integer` | +| | Method name or property name of the caller. | `String` | +| | String representation of the argument expression. | `String` | This information helps you with tracing and debugging, and helps you to create diagnostic tools. The following example shows how to use caller info attributes. On each call to the `TraceMessage` method, the caller information is inserted for the arguments to the optional parameters. :::code language="csharp" source="./snippets/CallerInformation.cs" id="CallerFileMemberLine"::: -You specify an explicit default value for each optional parameter. You can't apply caller info attributes to parameters that aren't specified as optional. The caller info attributes don't make a parameter optional. Instead, they affect the default value passed in when the argument is omitted. Caller info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the property for exceptions, obfuscation doesn't affect the results. You can explicitly supply the optional arguments to control the caller information or to hide caller information. +You specify an explicit default value for each optional parameter. You can't apply caller info attributes to parameters that aren't optional. The caller info attributes don't make a parameter optional. Instead, they affect the default value passed in when the argument is omitted. The compiler emits caller info values as literals into the Intermediate Language (IL) at compile time. Unlike the results of the property for exceptions, obfuscation doesn't affect the results. You can explicitly supply the optional arguments to control the caller information or to hide caller information. ## Member names -You can use the `CallerMemberName` attribute to avoid specifying the member name as a `String` argument to the called method. By using this technique, you avoid the problem that **Rename Refactoring** doesn't change the `String` values. This benefit is especially useful for the following tasks: +Use the `CallerMemberName` attribute to avoid specifying the member name as a `String` argument to the called method. By using this technique, you avoid the problem that **Rename Refactoring** doesn't change the `String` values. This benefit is especially useful for the following tasks: - Using tracing and diagnostic routines. - Implementing the interface when binding data. This interface allows the property of an object to notify a bound control that the property changed. The control can display the updated information. Without the `CallerMemberName` attribute, you must specify the property name as a literal. The following chart shows the member names that are returned when you use the `CallerMemberName` attribute. -| Calls occur within | Member name result | -|-|-| -| Method, property, or event | The name of the method, property, or event from which the call originated.| -| Constructor | The string ".ctor" | -| Static constructor | The string ".cctor" | -| Finalizer | The string "Finalize" | +| Calls occur within | Member name result | +|---------------------------------------|-----------------------| +| Method, property, or event | The name of the method, property, or event from which the call originated.| +| Constructor | The string ".ctor" | +| Static constructor | The string ".cctor" | +| Finalizer | The string "Finalize" | | User-defined operators or conversions | The generated name for the member, for example, "op_Addition". | -| Attribute constructor | The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member associated with that element. | +| Attribute constructor | The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member associated with that element. | | No containing member (for example, assembly-level or attributes that are applied to types) | The default value of the optional parameter. | ## Argument expressions -You use the when you want the expression passed as an argument. Diagnostic libraries can provide more details about the *expressions* passed to arguments. By providing the expression that triggered the diagnostic, in addition to the parameter name, developers have more details about the condition that triggered the diagnostic. That extra information makes it easier to fix. +Use the when you want the expression passed as an argument. Diagnostic libraries can provide more details about the *expressions* passed to arguments. By providing the expression that triggered the diagnostic, in addition to the parameter name, developers have more details about the condition that triggered the diagnostic. That extra information makes it easier to fix. The following example shows how you can provide detailed information about the argument when it's invalid: :::code language="csharp" source="./snippets/CallerInformation.cs" id="TestCondition"::: -You would invoke it as shown in the following example: +You invoke it as shown in the following example: :::code language="csharp" source="./snippets/CallerInformation.cs" id="InvokeTestCondition"::: @@ -58,7 +62,7 @@ The compiler injects the expression used for `condition` into the `message` argu Argument failed validation: ``` -This attribute enables you to write diagnostic utilities that provide more details. Developers can more quickly understand what changes are needed. You can also use the to determine what expression was used as the receiver for extension members. The following method samples a sequence at regular intervals. If the sequence has fewer elements than the frequency, it reports an error: +By using this attribute, you can write diagnostic utilities that provide more details. Developers can more quickly understand what changes are needed. You can also use the to determine what expression was used as the receiver for extension members. The following method samples a sequence at regular intervals. If the sequence has fewer elements than the frequency, it reports an error: :::code language="csharp" source="./snippets/CallerInformation.cs" id="ExtensionMethod"::: @@ -66,7 +70,7 @@ The previous example uses the [`nameof`](../operators/nameof.md) operator for th :::code language="csharp" source="./snippets/Program.cs" id="ShortSequence"::: -The preceding example would throw an whose message is the following text: +The preceding example throws an whose message is the following text: ```text Expression doesn't have enough elements: Enumerable.Range(0, 10) (Parameter 'sequence') diff --git a/docs/csharp/language-reference/attributes/general.md b/docs/csharp/language-reference/attributes/general.md index 3c24b5edba55d..2a2ec2db45f29 100644 --- a/docs/csharp/language-reference/attributes/general.md +++ b/docs/csharp/language-reference/attributes/general.md @@ -1,11 +1,13 @@ --- title: "Attributes interpreted by the compiler: Miscellaneous" -ms.date: 01/24/2025 +ms.date: 01/14/2026 description: "Learn about attributes that affect code generated by the compiler: the Conditional, Obsolete, AttributeUsage, ModuleInitializer, and SkipLocalsInit attributes." --- # Miscellaneous attributes interpreted by the C# compiler -There are several attributes that can be applied to elements in your code that add semantic meaning to those elements: +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +You can apply several attributes to elements in your code to add semantic meaning to those elements: - [`Conditional`](#conditional-attribute): Make execution of a method dependent on a preprocessor identifier. - [`Obsolete`](#obsolete-and-deprecated-attribute): Mark a type or member for (potential) future removal. diff --git a/docs/csharp/language-reference/attributes/global.md b/docs/csharp/language-reference/attributes/global.md index cfd64d0afa665..a4b318521e2b5 100644 --- a/docs/csharp/language-reference/attributes/global.md +++ b/docs/csharp/language-reference/attributes/global.md @@ -1,19 +1,21 @@ --- title: "Attributes interpreted by the compiler: Global attributes" -ms.date: 07/26/2024 +ms.date: 01/14/2026 description: Attributes provide metadata the compiler uses to understand more semantics of your program --- # Assembly level attributes interpreted by the C# compiler -Most attributes are applied to specific language elements such as classes or methods; however, some attributes are global—they apply to an entire assembly or module. For example, the attribute can be used to embed version information into an assembly, like this: +Most attributes apply to specific language elements such as classes or methods. However, some attributes are global. They apply to an entire assembly or module. For example, use the attribute to embed version information into an assembly, like this: ```csharp [assembly: AssemblyVersion("1.0.0.0")] ``` -Global attributes appear in the source code after any top level `using` directives and before any type, module, or namespace declarations. Global attributes can appear in multiple source files, but the files must be compiled in a single compilation pass. Visual Studio adds global attributes to the AssemblyInfo.cs file in .NET Framework projects. These attributes aren't added to .NET Core projects. +Global attributes appear in the source code after any top level `using` directives and before any type, module, or namespace declarations. You can include global attributes in multiple source files, but you must compile the files in a single compilation pass. In .NET Framework projects, Visual Studio adds global attributes to the AssemblyInfo.cs file. These attributes aren't added to .NET Core projects. -Assembly attributes are values that provide information about an assembly. They fall into the following categories: +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +Assembly attributes provide information about an assembly. They fall into the following categories: - Assembly identity attributes - Informational attributes @@ -21,37 +23,37 @@ Assembly attributes are values that provide information about an assembly. They ## Assembly identity attributes -Three attributes (with a strong name, if applicable) determine the identity of an assembly: name, version, and culture. These attributes form the full name of the assembly and are required when you reference it in code. You can set an assembly's version and culture using attributes. However, the name value is set by the compiler, the Visual Studio IDE in the [Assembly Information Dialog Box](/visualstudio/ide/reference/assembly-information-dialog-box), or the Assembly Linker (Al.exe) when the assembly is created. The assembly name is based on the assembly manifest. The attribute specifies whether multiple copies of the assembly can coexist. +Three attributes (with a strong name, if applicable) determine the identity of an assembly: name, version, and culture. These attributes form the full name of the assembly and are required when you reference it in code. You can set an assembly's version and culture by using attributes. However, you set the name value by the compiler, the Visual Studio IDE in the [Assembly Information Dialog Box](/visualstudio/ide/reference/assembly-information-dialog-box), or the Assembly Linker (Al.exe) when you create the assembly. The assembly name is based on the assembly manifest. The attribute specifies whether multiple copies of the assembly can coexist. The following table shows the identity attributes. -|Attribute|Purpose| -|---------------|-------------| -||Specifies the version of an assembly.| -||Specifies which culture the assembly supports.| -||Specifies a bitwise combination of flags for an assembly, describing just-in-time (JIT) compiler options, whether the assembly is retargetable, and whether it has a full or tokenized public key. | +| Attribute | Purpose | +|---------------------------------------------------|------------------------------------------------| +| | Specifies the version of an assembly. | +| | Specifies which culture the assembly supports. | +| | Specifies a bitwise combination of flags for an assembly, describing just-in-time (JIT) compiler options, whether the assembly is retargetable, and whether it has a full or tokenized public key. | ## Informational attributes -You use informational attributes to provide more company or product information for an assembly. The following table shows the informational attributes defined in the namespace. +Use informational attributes to provide more company or product information for an assembly. The following table shows the informational attributes defined in the namespace. -|Attribute|Purpose| -|---------------|-------------| -||Specifies a product name for an assembly manifest.| -||Specifies a trademark for an assembly manifest.| -||Specifies an informational version for an assembly manifest.| -||Specifies a company name for an assembly manifest.| -||Defines a custom attribute that specifies a copyright for an assembly manifest.| -||Sets a specific version number for the Win32 file version resource.| -||Indicates whether the assembly is compliant with the Common Language Specification (CLS).| +| Attribute | Purpose | +|----------------------------------------------------------------|--------------------------------------------------------------| +| | Specifies a product name for an assembly manifest. | +| | Specifies a trademark for an assembly manifest. | +| | Specifies an informational version for an assembly manifest. | +| | Specifies a company name for an assembly manifest. | +| | Defines a custom attribute that specifies a copyright for an assembly manifest. | +| | Sets a specific version number for the Win32 file version resource. | +| | Indicates whether the assembly is compliant with the Common Language Specification (CLS). | ## Assembly manifest attributes -You can use assembly manifest attributes to provide information in the assembly manifest. The attributes include title, description, default alias, and configuration. The following table shows the assembly manifest attributes defined in the namespace. +Use assembly manifest attributes to provide information in the assembly manifest. The attributes include title, description, default alias, and configuration. The following table shows the assembly manifest attributes defined in the namespace. -|Attribute|Purpose| -|---------------|-------------| -||Specifies an assembly title for an assembly manifest.| -||Specifies an assembly description for an assembly manifest.| -||Specifies an assembly configuration (such as retail or debug) for an assembly manifest.| -||Defines a friendly default alias for an assembly manifest| +| Attribute | Purpose | +|---------------------------------------------------------|-------------------------------------------------------------| +| | Specifies an assembly title for an assembly manifest. | +| | Specifies an assembly description for an assembly manifest. | +| | Specifies an assembly configuration (such as retail or debug) for an assembly manifest. | +| | Defines a friendly default alias for an assembly manifest. | diff --git a/docs/csharp/language-reference/attributes/nullable-analysis.md b/docs/csharp/language-reference/attributes/nullable-analysis.md index 513b8da04cec4..2bc55795b5700 100644 --- a/docs/csharp/language-reference/attributes/nullable-analysis.md +++ b/docs/csharp/language-reference/attributes/nullable-analysis.md @@ -1,7 +1,7 @@ --- title: "Attributes interpreted by the compiler: Nullable static analysis" description: Learn about attributes interpreted by the compiler to provide better static analysis for nullable and non-nullable reference types. -ms.date: 11/18/2025 +ms.date: 01/14/2026 --- # Attributes for null-state static analysis interpreted by the C# compiler @@ -12,6 +12,8 @@ In a nullable enabled context, the compiler performs static analysis of code to These states enable the compiler to provide warnings when you might dereference a null value, throwing a . These attributes provide the compiler with semantic information about the *null-state* of arguments, return values, and object members. The attributes clarify the state of arguments and return values. The compiler provides more accurate warnings when your APIs are properly annotated with this semantic information. +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + This article provides a brief description of each of the nullable reference type attributes and how to use them. Let's start with an example. Imagine your library has the following API that retrieves a resource string. This method was originally compiled in a *nullable oblivious* context: @@ -24,7 +26,7 @@ The preceding example follows the familiar `Try*` pattern in .NET. There are two - Callers can pass a variable whose value is `null` as the argument for `message`. - If the `TryGetMessage` method returns `true`, the value of `message` isn't null. If the return value is `false`, the value of `message` is null. -The rule for `key` can be expressed succinctly: `key` should be a non-nullable reference type. The `message` parameter is more complex. It allows a variable that is `null` as the argument, but guarantees, on success, that the `out` argument isn't `null`. For these scenarios, you need a richer vocabulary to describe the expectations. The [`NotNullWhen`](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) attribute describes the *null-state* for the argument used for the `message` parameter. +The rule for `key` can be expressed succinctly: `key` should be a non-nullable reference type. The `message` parameter is more complex. It allows a variable that is null as the argument, but guarantees, on success, that the `out` argument isn't null. For these scenarios, you need a richer vocabulary to describe the expectations. The [`NotNullWhen`](#conditional-postconditions-notnullwhen-maybenullwhen-and-notnullifnotnull) attribute describes the *null-state* for the argument used for the `message` parameter. > [!NOTE] > Adding these attributes gives the compiler more information about the rules for your API. When calling code is compiled in a nullable enabled context, the compiler warns callers when they violate those rules. These attributes don't enable more checks on your implementation. @@ -35,9 +37,9 @@ The rule for `key` can be expressed succinctly: `key` should be a non-nullable r | [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute) | [Precondition](#preconditions-allownull-and-disallownull) | A nullable parameter, field, or property should never be null. | | [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute) | [Postcondition](#postconditions-maybenull-and-notnull) | A non-nullable parameter, field, property, or return value might be null. | | [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute) | [Postcondition](#postconditions-maybenull-and-notnull) | A nullable parameter, field, property, or return value is never null. | -| [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A non-nullable argument might be null when the method returns the specified `bool` value. | -| [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A nullable argument isn't null when the method returns the specified `bool` value. | -| [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A return value, property, or argument isn't null if the argument for the specified parameter isn't null. | +| [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute) | [Conditional postcondition](#conditional-postconditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A non-nullable argument might be null when the method returns the specified `bool` value. | +| [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute) | [Conditional postcondition](#conditional-postconditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A nullable argument isn't null when the method returns the specified `bool` value. | +| [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute) | [Conditional postcondition](#conditional-postconditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A return value, property, or argument isn't null if the argument for the specified parameter isn't null. | | [MemberNotNull](xref:System.Diagnostics.CodeAnalysis.MemberNotNullAttribute) | [Method and property helper methods](#helper-methods-membernotnull-and-membernotnullwhen) | The listed member isn't null when the method returns. | | [MemberNotNullWhen](xref:System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute) | [Method and property helper methods](#helper-methods-membernotnull-and-membernotnullwhen) | The listed member isn't null when the method returns the specified `bool` value. | | [DoesNotReturn](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute) | [Unreachable code](#stop-nullable-analysis-when-called-method-throws) | A method or property never returns. In other words, it always throws an exception. | @@ -51,7 +53,7 @@ Consider a read/write property that never returns `null` because it has a reason :::code language="csharp" source="snippets/NullableAttributes.cs" ID="PropertyExample" ::: -When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable reference types, the `ScreenName` property becomes a non-nullable reference. Callers don't need to check the returned property for `null`. But now setting the property to `null` generates a warning. To support this type of code, you add the attribute to the property, as shown in the following code: +When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable reference types, the `ScreenName` property becomes a non-nullable reference. Callers don't need to check the returned property for `null`. But now setting the property to `null` generates a warning. To support this type of code, add the attribute to the property, as shown in the following code: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="AllowNullableProperty" ::: @@ -64,7 +66,7 @@ The preceding example demonstrates what to look for when adding the `AllowNull` Most often you need this attribute for properties, or `in`, `out`, and `ref` arguments. The `AllowNull` attribute is the best choice when a variable is typically non-null, but you need to allow `null` as a precondition. -Contrast that with scenarios for using `DisallowNull`: You use this attribute to specify that an argument of a nullable reference type shouldn't be `null`. Consider a property where `null` is the default value, but clients can only set it to a non-null value. Consider the following code: +Contrast that condition with scenarios for using `DisallowNull`: Use this attribute to specify that an argument of a nullable reference type shouldn't be `null`. Consider a property where `null` is the default value, but clients can only set it to a non-null value. Consider the following code: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="MessagingExample" ::: @@ -72,7 +74,7 @@ The preceding code is the best way to express your design that the `ReviewCommen :::code language="csharp" source="snippets/NullableAttributes.cs" ID="DisallowNullProperty" ::: -In a nullable context, the `ReviewComment` `get` accessor could return the default value of `null`. The compiler warns that it must be checked before access. Furthermore, it warns callers that, even though it could be `null`, callers shouldn't explicitly set it to `null`. The `DisallowNull` attribute also specifies a *pre-condition*, it doesn't affect the `get` accessor. You use the `DisallowNull` attribute when you observe these characteristics about: +In a nullable context, the `ReviewComment` `get` accessor could return the default value of `null`. The compiler warns that it must be checked before access. Furthermore, it warns callers that, even though it could be `null`, callers shouldn't explicitly set it to `null`. The `DisallowNull` attribute also specifies a *pre-condition*, it doesn't affect the `get` accessor. Use the `DisallowNull` attribute when you observe these characteristics: 1. The variable could be `null` in core scenarios, often when first instantiated. 1. The variable shouldn't be explicitly set to `null`. @@ -92,7 +94,7 @@ Suppose you have a method with the following signature: public Customer FindCustomer(string lastName, string firstName) ``` -You likely wrote a method like this to return `null` when the name sought wasn't found. The `null` clearly indicates that the record wasn't found. In this example, you'd likely change the return type from `Customer` to `Customer?`. Declaring the return value as a nullable reference type specifies the intent of this API clearly: +You likely wrote a method like this to return `null` when the name sought isn't found. The `null` value clearly indicates that the record wasn't found. In this example, you'd likely change the return type from `Customer` to `Customer?`. Declaring the return value as a nullable reference type specifies the intent of this API clearly: ```csharp public Customer? FindCustomer(string lastName, string firstName) @@ -122,24 +124,24 @@ After enabling null reference types, you want to ensure that the preceding code The preceding code expresses the existing contract clearly: Callers can pass a variable with the `null` value, but the argument is guaranteed to never be null if the method returns without throwing an exception. -You specify unconditional postconditions using the following attributes: +You specify unconditional postconditions by using the following attributes: - [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value can be null. - [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value is never null. -## Conditional post-conditions: `NotNullWhen`, `MaybeNullWhen`, and `NotNullIfNotNull` +## Conditional postconditions: `NotNullWhen`, `MaybeNullWhen`, and `NotNullIfNotNull` -You're likely familiar with the `string` method . This method returns `true` when the argument is null or an empty string. It's a form of null-check: Callers don't need to null-check the argument if the method returns `false`. To make a method like this nullable aware, you'd set the argument to a nullable reference type, and add the `NotNullWhen` attribute: +You're likely familiar with the `string` method . This method returns `true` when the argument is null or an empty string. It's a form of null-check: Callers don't need to null-check the argument if the method returns `false`. To make a method like this nullable aware, set the argument to a nullable reference type, and add the `NotNullWhen` attribute: ```csharp bool IsNullOrEmpty([NotNullWhen(false)] string? value) ``` -That informs the compiler that any code where the return value is `false` doesn't need null checks. The addition of the attribute informs the compiler's static analysis that `IsNullOrEmpty` performs the necessary null check: when it returns `false`, the argument isn't `null`. +That change informs the compiler that any code where the return value is `false` doesn't need null checks. The addition of the attribute informs the compiler's static analysis that `IsNullOrEmpty` performs the necessary null check: when it returns `false`, the argument isn't `null`. :::code language="csharp" source="snippets/NullableAttributes.cs" ID="NullCheckExample" ::: -The method is as shown in the previous example. You might have similar methods in your codebase that check the state of objects for null values. The compiler doesn't recognize custom null check methods, and you need to add the annotations yourself. When you add the attribute, the compiler's static analysis knows when the tested variable is null-checked. +The method is as shown in the preceding example. You might have similar methods in your codebase that check the state of objects for null values. The compiler doesn't recognize custom null check methods, and you need to add the annotations yourself. When you add the attribute, the compiler's static analysis knows when the tested variable is null-checked. Another use for these attributes is the `Try*` pattern. The postconditions for `ref` and `out` arguments are communicated through the return value. Consider this method shown earlier (in a nullable disabled context): @@ -151,9 +153,9 @@ In a nullable enabled context, you can communicate that idiom using the `NotNull :::code language="csharp" source="snippets/NullableAttributes.cs" ID="NotNullWhenTryGet" ::: -In the preceding example, the value of `message` is known to be not null when `TryGetMessage` returns `true`. You should annotate similar methods in your codebase in the same way: the arguments could equal `null`, and are known to be not null when the method returns `true`. +In the preceding example, the value of `message` is known to be not null when `TryGetMessage` returns `true`. You should annotate similar methods in your codebase in the same way: the arguments could be `null`, and are known to be not null when the method returns `true`. -There's one final attribute you might also need. Sometimes the null state of a return value depends on the null state of one or more arguments. These methods return a non-null value whenever certain arguments aren't `null`. To correctly annotate these methods, you use the `NotNullIfNotNull` attribute. Consider the following method: +There's one final attribute you might also need. Sometimes the null state of a return value depends on the null state of one or more arguments. These methods return a non-null value whenever certain arguments aren't `null`. To correctly annotate these methods, use the `NotNullIfNotNull` attribute. Consider the following method: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="ExtractComponent" ::: @@ -163,11 +165,11 @@ If the `url` argument isn't null, the output isn't `null`. Once nullable referen string? GetTopLevelDomainFromFullUrl(string? url) ``` -That also works, but often forces callers to implement extra `null` checks. The contract is that the return value would be `null` only when the argument `url` is `null`. To express that contract, you would annotate this method as shown in the following code: +That annotation also works, but often forces callers to implement extra `null` checks. The contract is that the return value is `null` only when the argument `url` is `null`. To express that contract, annotate this method as shown in the following code: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="ExtractComponentIfNotNull" ::: -The previous example uses the [`nameof`](../operators/nameof.md) operator for the parameter `url`. The return value and the argument have both been annotated with the `?` indicating that either could be `null`. The attribute further clarifies that the return value isn't null when the `url` argument isn't `null`. +The previous example uses the [`nameof`](../operators/nameof.md) operator for the parameter `url`. The return value and the argument are both annotated with the `?` indicating that either could be `null`. The attribute further clarifies that the return value isn't null when the `url` argument isn't `null`. You specify conditional postconditions using these attributes: @@ -177,25 +179,25 @@ You specify conditional postconditions using these attributes: ## Helper methods: `MemberNotNull` and `MemberNotNullWhen` -These attributes specify your intent when you refactored common code from constructors into helper methods. The C# compiler analyzes constructors and field initializers to make sure that all non-nullable reference fields are initialized before each constructor returns. However, the C# compiler doesn't track field assignments through all helper methods. The compiler issues warning `CS8618` when fields aren't initialized directly in the constructor, but rather in a helper method. You add the to a method declaration and specify the fields that are initialized to a non-null value in the method. For example, consider the following example: +Use these attributes to specify your intent when you refactor common code from constructors into helper methods. The C# compiler analyzes constructors and field initializers to make sure that all non-nullable reference fields are initialized before each constructor returns. However, the C# compiler doesn't track field assignments through all helper methods. The compiler issues warning `CS8618` when fields aren't initialized directly in the constructor, but rather in a helper method. Add the to a method declaration and specify the fields that are initialized to a non-null value in the method. For example, consider the following example: :::code language="csharp" source="snippets/InitializeMembers.cs" ID="MemberNotNullExample"::: You can specify multiple field names as arguments to the `MemberNotNull` attribute constructor. -The has a `bool` argument. You use `MemberNotNullWhen` in situations where your helper method returns a `bool` indicating whether your helper method initialized fields. +The has a `bool` argument. Use `MemberNotNullWhen` in situations where your helper method returns a `bool` indicating whether your helper method initialized fields. ## Stop nullable analysis when called method throws Some methods, typically exception helpers, or other utility methods, always exit by throwing an exception. Or, a helper throws an exception based on the value of a Boolean argument. -In the first case, you can add the attribute to the method declaration. The compiler's *null-state* analysis doesn't check any code in a method that follows a call to a method annotated with `DoesNotReturn`. Consider this method: +In the first case, add the attribute to the method declaration. The compiler's *null-state* analysis doesn't check any code in a method that follows a call to a method annotated with `DoesNotReturn`. Consider this method: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="DoesNotReturn"::: The compiler doesn't issue any warnings after the call to `FailFast`. -In the second case, you add the attribute to a Boolean parameter of the method. You can modify the previous example as follows: +In the second case, add the attribute to a Boolean parameter of the method. You can modify the previous example as follows: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="DoesNotReturnIf"::: @@ -203,7 +205,7 @@ When the value of the argument matches the value of the `DoesNotReturnIf` constr ## Summary -Adding nullable reference types provides an initial vocabulary to describe your APIs expectations for variables that could be `null`. The attributes provide a richer vocabulary to describe the null state of variables as preconditions and postconditions. These attributes more clearly describe your expectations and provide a better experience for the developers using your APIs. +Adding nullable reference types provides an initial vocabulary to describe your API's expectations for variables that could be `null`. The attributes provide a richer vocabulary to describe the null state of variables as preconditions and postconditions. By using these attributes, you more clearly describe your expectations and provide a better experience for the developers using your APIs. As you update libraries for a nullable context, add these attributes to guide users of your APIs to the correct usage. These attributes help you fully describe the null-state of arguments and return values. diff --git a/docs/csharp/language-reference/attributes/pseudo-attributes.md b/docs/csharp/language-reference/attributes/pseudo-attributes.md index ff9d7b692cb96..07c87f33c02e0 100644 --- a/docs/csharp/language-reference/attributes/pseudo-attributes.md +++ b/docs/csharp/language-reference/attributes/pseudo-attributes.md @@ -1,11 +1,13 @@ --- title: "Attributes interpreted by the compiler: Pseudo-attributes" -ms.date: 01/28/2025 +ms.date: 01/14/2026 description: "Learn about attributes you can add to code that are written to IL as modifiers. These custom attributes aren't emitted as attributes in the compiled output." --- # Custom attributes that generate flags or options in the Intermediate Language (IL) output -You add these attributes to your code for the compiler to emit a specified Intermediate Language (IL) modifier. These attributes instruct the compiler to include the corresponding IL modifier in the output. +Add these attributes to your code for the compiler to emit a specified Intermediate Language (IL) modifier. These attributes instruct the compiler to include the corresponding IL modifier in the output. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] | Attribute | Modifier | Comments | |--------------------------------------------------------------------------------------|-----------------|-----------| @@ -19,9 +21,9 @@ You add these attributes to your code for the compiler to emit a specified Inter | | `preservesig` | | | | `serializable` | | | | `auto`, `sequential`, or `explicit` | Layout options can be set using the parameters. | -| | | You add this attribute to an indexer to set a different method name. By default, indexers are compiled to a property named `Item`. You can specify a different name using this attribute. | +| | | Add this attribute to an indexer to set a different method name. By default, indexers are compiled to a property named `Item`. You can specify a different name using this attribute. | -Some of these custom attributes are applied using other C# syntax rather than adding the attribute to your source code. +Some of these custom attributes are applied by using other C# syntax rather than adding the attribute to your source code. | Attribute | Comments | |--------------------------------------------------------------------------------------------------|----------| @@ -35,7 +37,7 @@ The following attributes are generally disallowed in C# source. They're listed h | Attribute | Comments | |--------------------------------------------------------------------------------------------------|---------| -| | Prevents downlevel compilers from using metadata it can't safely understand. | +| | Prevents downlevel compilers from using metadata they can't safely understand. | | | Encodes `const decimal` fields. The runtime doesn't support `decimal` values as constant values. | | | Encodes indexers with . This attribute notes the default indexer when its name is different than `Item`. This attribute is allowed in source. | | | Encodes whether a type in a signature is `dynamic` (versus `object`). | diff --git a/docs/csharp/language-reference/builtin-types/arrays.md b/docs/csharp/language-reference/builtin-types/arrays.md index cf2b8ad47917e..cf248ad0d03c7 100644 --- a/docs/csharp/language-reference/builtin-types/arrays.md +++ b/docs/csharp/language-reference/builtin-types/arrays.md @@ -1,7 +1,7 @@ --- title: "The array reference type" description: Store multiple variables of the same type in an array data structure in C#. Declare an array by specifying a type or specify Object to store any type. -ms.date: 12/09/2024 +ms.date: 01/14/2026 helpviewer_keywords: - "arrays [C#]" - "C# language, arrays" @@ -20,13 +20,15 @@ helpviewer_keywords: --- # Arrays -You can store multiple variables of the same type in an array data structure. You declare an array by specifying the type of its elements. If you want the array to store elements of any type, you can specify `object` as its type. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from . +You can store multiple variables of the same type in an array data structure. You declare an array by specifying the type of its elements. If you want the array to store elements of any type, specify `object` as its type. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from . + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] ```csharp type[] arrayName; ``` -An array is a reference type, so the array can be a [nullable reference](../../nullable-references.md) type. The element types might be reference types, so an array can be declared to hold nullable reference types. The following example declarations show the different syntax used to declare the nullability of the array or the elements: +An array is a reference type, so the array can be a [nullable reference](../../nullable-references.md) type. The element types might be reference types, so you can declare an array to hold nullable reference types. The following example declarations show the different syntax used to declare the nullability of the array or the elements: ```csharp type?[] arrayName; // non nullable array of nullable element types. @@ -47,13 +49,13 @@ string[] messages = new string[10]; // All values are null. An array has the following properties: - An array can be [single-dimensional](#single-dimensional-arrays), [multidimensional](#multidimensional-arrays), or [jagged](#jagged-arrays). -- The number of dimensions are set when an array variable is declared. The length of each dimension is established when the array instance is created. These values can't be changed during the lifetime of the instance. +- The number of dimensions is set when you declare an array variable. You establish the length of each dimension when you create the array instance. You can't change these values during the lifetime of the instance. - A jagged array is an array of arrays, and each member array has the default value of `null`. - Arrays are zero indexed: an array with `n` elements is indexed from `0` to `n-1`. - Array elements can be of any type, including an array type. - Array types are [reference types](../keywords/reference-types.md) derived from the abstract base type . All arrays implement and . You can use the [foreach](../statements/iteration-statements.md#the-foreach-statement) statement to iterate through an array. Single-dimensional arrays also implement and . -The elements of an array can be initialized to known values when the array is created. Beginning with C# 12, all of the collection types can be initialized using a [Collection expression](../operators/collection-expressions.md). Elements that aren't initialized are set to the [default value](default-values.md). The default value is the 0-bit pattern. All reference types (including [non-nullable](../../nullable-references.md#known-pitfalls) types), have the values `null`. All value types have the 0-bit patterns. That means the property is `false` and the property is undefined. In the .NET implementation, the `Value` property throws an exception. +You can initialize the elements of an array to known values when you create the array. Beginning with C# 12, you can use a [Collection expression](../operators/collection-expressions.md) to initialize all of the collection types. Elements that you don't initialize are set to the [default value](default-values.md). The default value is the 0-bit pattern. All reference types (including [non-nullable](../../nullable-references.md#known-pitfalls) types) have the value `null`. All value types have the 0-bit patterns. That means the property is `false` and the property is undefined. In the .NET implementation, the `Value` property throws an exception. The following example creates single-dimensional, multidimensional, and jagged arrays: @@ -71,7 +73,7 @@ The following example creates single-dimensional, multidimensional, and jagged a ## Single-dimensional arrays -A *single-dimensional array* is a sequence of like elements. You access an element via its *index*. The *index* is its ordinal position in the sequence. The first element in the array is at index `0`. You create a single-dimensional array using the [new](../operators/new-operator.md) operator specifying the array element type and the number of elements. The following example declares and initializes single-dimensional arrays: +A *single-dimensional array* is a sequence of like elements. You access an element through its *index*. The *index* is the element's ordinal position in the sequence. The first element in the array is at index `0`. You create a single-dimensional array by using the [new](../operators/new-operator.md) operator and specifying the array element type and the number of elements. The following example declares and initializes single-dimensional arrays: :::code language="csharp" source="snippets/shared/Arrays.cs" id="SingleDimensionalArrayDeclaration"::: @@ -91,29 +93,29 @@ Arrays can have more than one dimension. For example, the following declarations :::code language="csharp" source="./snippets/shared/Arrays.cs" id="MultiDimensionalArrayDeclaration"::: -For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are incremented first, then the next left dimension, and so on, to the leftmost index. The following example enumerates both a 2D and a 3D array: +For multidimensional arrays, traversal increments the indices of the rightmost dimension first, then the next left dimension, and so on, to the leftmost index. The following example enumerates both a 2D and a 3D array: :::code language="csharp" source="./snippets/shared/Arrays.cs" id="ForeachMultiDimension"::: In a 2D array, you can think of the left index as the *row* and the right index as the *column*. -However, with multidimensional arrays, using a nested [for](../statements/iteration-statements.md#the-for-statement) loop gives you more control over the order in which to process the array elements: +However, with multidimensional arrays, using a nested [for](../statements/iteration-statements.md#the-for-statement) loop gives you more control over the order in which you process the array elements: :::code language="csharp" source="./snippets/shared/Arrays.cs" id="ForMultiDimension"::: ### Pass multidimensional arrays as arguments -You pass an initialized multidimensional array to a method in the same way that you pass a one-dimensional array. The following code shows a partial declaration of a print method that accepts a two-dimensional array as its argument. You can initialize and pass a new array in one step, as is shown in the following example. In the following example, a two-dimensional array of integers is initialized and passed to the `Print2DArray` method. The method displays the elements of the array. +Pass an initialized multidimensional array to a method the same way you pass a one-dimensional array. The following code shows a partial declaration of a print method that accepts a two-dimensional array as its argument. You can initialize and pass a new array in one step, as shown in the following example. In the following example, a two-dimensional array of integers is initialized and passed to the `Print2DArray` method. The method displays the elements of the array. :::code language="csharp" source="./snippets/shared/Arrays.cs" id="MultiDimensionParameter"::: ## Jagged arrays -A jagged array is an array whose elements are arrays, possibly of different sizes. A jagged array is sometimes called an "array of arrays." Its elements are reference types and are initialized to `null`. The following examples show how to declare, initialize, and access jagged arrays. The first example, `jaggedArray`, is declared in one statement. Each contained array is created in subsequent statements. The second example, `jaggedArray2` is declared and initialized in one statement. It's possible to mix jagged and multidimensional arrays. The final example, `jaggedArray3`, is a declaration and initialization of a single-dimensional jagged array that contains three two-dimensional array elements of different sizes. +A jagged array is an array whose elements are arrays, possibly of different sizes. A jagged array is sometimes called an "array of arrays." Its elements are reference types and are initialized to `null`. The following examples show how to declare, initialize, and access jagged arrays. The first example, `jaggedArray`, is declared in one statement. Each contained array is created in subsequent statements. The second example, `jaggedArray2` is declared and initialized in one statement. You can mix jagged and multidimensional arrays. The final example, `jaggedArray3`, is a declaration and initialization of a single-dimensional jagged array that contains three two-dimensional array elements of different sizes. :::code language="csharp" source="./snippets/shared/Arrays.cs" id="JaggedArrayDeclaration"::: -A jagged array's elements must be initialized before you can use them. Each of the elements is itself an array. It's also possible to use initializers to fill the array elements with values. When you use initializers, you don't need the array size. +You must initialize a jagged array's elements before you can use them. Each of the elements is itself an array. You can also use initializers to fill the array elements with values. When you use initializers, you don't need the array size. This example builds an array whose elements are themselves arrays. Each one of the array elements has a different size. diff --git a/docs/csharp/language-reference/builtin-types/bool.md b/docs/csharp/language-reference/builtin-types/bool.md index 6a3cfb9cbb70c..34b33c9a5253d 100644 --- a/docs/csharp/language-reference/builtin-types/bool.md +++ b/docs/csharp/language-reference/builtin-types/bool.md @@ -1,7 +1,7 @@ --- description: Learn about the built-in boolean type in C# title: "bool type" -ms.date: 11/26/2019 +ms.date: 01/14/2026 f1_keywords: - bool - bool_CSharpKeyword @@ -12,31 +12,32 @@ f1_keywords: helpviewer_keywords: - "bool data type [C#]" - "Boolean [C#]" -ms.assetid: 551cfe35-2632-4343-af49-33ad12da08e2 --- # bool (C# reference) The `bool` type keyword is an alias for the .NET structure type that represents a Boolean value, which can be either `true` or `false`. +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + To perform logical operations with values of the `bool` type, use [Boolean logical](../operators/boolean-logical-operators.md) operators. The `bool` type is the result type of [comparison](../operators/comparison-operators.md) and [equality](../operators/equality-operators.md) operators. A `bool` expression can be a controlling conditional expression in the [if](../statements/selection-statements.md#the-if-statement), [do](../statements/iteration-statements.md#the-do-statement), [while](../statements/iteration-statements.md#the-while-statement), and [for](../statements/iteration-statements.md#the-for-statement) statements and in the [conditional operator `?:`](../operators/conditional-operator.md). The default value of the `bool` type is `false`. ## Literals -You can use the `true` and `false` literals to initialize a `bool` variable or to pass a `bool` value: +Use the `true` and `false` literals to initialize a `bool` variable or to pass a `bool` value: -[!code-csharp[bool literals](snippets/shared/BoolType.cs#Literals)] +:::code language="csharp" source="snippets/shared/BoolType.cs" id="Literals"::: ## Three-valued Boolean logic -Use the nullable `bool?` type, if you need to support the three-valued logic, for example, when you work with databases that support a three-valued Boolean type. For the `bool?` operands, the predefined `&` and `|` operators support the three-valued logic. For more information, see the [Nullable Boolean logical operators](../operators/boolean-logical-operators.md#nullable-boolean-logical-operators) section of the [Boolean logical operators](../operators/boolean-logical-operators.md) article. +Use the nullable `bool?` type if you need to support three-valued logic. For example, use it when you work with databases that support a three-valued Boolean type. For the `bool?` operands, the predefined `&` and `|` operators support the three-valued logic. For more information, see the [Nullable Boolean logical operators](../operators/boolean-logical-operators.md#nullable-boolean-logical-operators) section of the [Boolean logical operators](../operators/boolean-logical-operators.md) article. For more information about nullable value types, see [Nullable value types](nullable-value-types.md). ## Conversions -C# provides only two conversions that involve the `bool` type. Those are an implicit conversion to the corresponding nullable `bool?` type and an explicit conversion from the `bool?` type. However, .NET provides additional methods that you can use to convert to or from the `bool` type. For more information, see the [Converting to and from Boolean values](/dotnet/api/system.boolean#converting-to-and-from-boolean-values) section of the API reference page. +C# provides only two conversions that involve the `bool` type. Those conversions are an implicit conversion to the corresponding nullable `bool?` type and an explicit conversion from the `bool?` type. However, .NET provides additional methods that you can use to convert to or from the `bool` type. For more information, see the [Converting to and from Boolean values](/dotnet/api/system.boolean#converting-to-and-from-boolean-values) section of the API reference page. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/built-in-types.md b/docs/csharp/language-reference/builtin-types/built-in-types.md index 1552091b27f1f..eeba6b19451fc 100644 --- a/docs/csharp/language-reference/builtin-types/built-in-types.md +++ b/docs/csharp/language-reference/builtin-types/built-in-types.md @@ -1,7 +1,7 @@ --- title: "Built-in types" description: "Learn C# built-in value and reference types" -ms.date: 11/24/2025 +ms.date: 01/14/2026 helpviewer_keywords: - "types [C#], built-in" - "built-in C# types" @@ -37,6 +37,8 @@ The following table lists the C# built-in [reference](../keywords/reference-type | [`delegate`](reference-types.md#the-delegate-type) | | | [`dynamic`](reference-types.md#the-dynamic-type) | | +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + In the preceding tables, most C# type keywords from the left column are aliases for the corresponding .NET type. They're interchangeable. For example, the following declarations declare variables of the same type: ```csharp diff --git a/docs/csharp/language-reference/builtin-types/char.md b/docs/csharp/language-reference/builtin-types/char.md index d182506adb179..6acf80a6be691 100644 --- a/docs/csharp/language-reference/builtin-types/char.md +++ b/docs/csharp/language-reference/builtin-types/char.md @@ -1,7 +1,7 @@ --- description: Learn about the built-in character type in C# title: "The char type" -ms.date: 02/27/2025 +ms.date: 01/14/2026 f1_keywords: - "char" - "char_CSharpKeyword" @@ -10,21 +10,23 @@ helpviewer_keywords: --- # char (C# reference) -The `char` type keyword is an alias for the .NET structure type that represents a Unicode UTF-16 code unit, typically a UTF-16 character. +The `char` type keyword is an alias for the .NET structure type. It represents a Unicode UTF-16 code unit, typically a UTF-16 character. | Type | Range | Size | .NET type | |--------|------------------|--------|-------------------------------------------------| | `char` | U+0000 to U+FFFF | 16 bit | | -The default value of the `char` type is `\0`, that is, U+0000. +The default value of the `char` type is `\0`, which is U+0000. -The `char` type supports [comparison](../operators/comparison-operators.md), [equality](../operators/equality-operators.md), [increment](../operators/arithmetic-operators.md#increment-operator-), and [decrement](../operators/arithmetic-operators.md#decrement-operator---) operators. Moreover, for `char` operands, [arithmetic](../operators/arithmetic-operators.md) and [bitwise logical](../operators/bitwise-and-shift-operators.md) operators perform an operation on the corresponding code points and produce the result as an `int` value. +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +The `char` type supports [comparison](../operators/comparison-operators.md), [equality](../operators/equality-operators.md), [increment](../operators/arithmetic-operators.md#increment-operator-), and [decrement](../operators/arithmetic-operators.md#decrement-operator---) operators. For `char` operands, [arithmetic](../operators/arithmetic-operators.md) and [bitwise logical](../operators/bitwise-and-shift-operators.md) operators perform an operation on the corresponding code points and produce the result as an `int` value. The [string](reference-types.md#the-string-type) type represents text as a sequence of `char` values. ## Literals -You can specify a `char` value with: +You can specify a `char` value by using: - a character literal. - a Unicode escape sequence, which is `\u` followed by the four-symbol hexadecimal representation of a character code. @@ -41,9 +43,9 @@ As the preceding example shows, you can also cast the value of a character code ## Conversions -The `char` type is implicitly convertible to the following [integral](integral-numeric-types.md) types: `ushort`, `int`, `uint`, `long`, `ulong`, `nint`, and `nuint`. It's also implicitly convertible to the built-in [floating-point](floating-point-numeric-types.md) numeric types: `float`, `double`, and `decimal`. It's explicitly convertible to `sbyte`, `byte`, and `short` integral types. +The `char` type implicitly converts to the following [integral](integral-numeric-types.md) types: `ushort`, `int`, `uint`, `long`, `ulong`, `nint`, and `nuint`. It also implicitly converts to the built-in [floating-point](floating-point-numeric-types.md) numeric types: `float`, `double`, and `decimal`. It explicitly converts to `sbyte`, `byte`, and `short` integral types. -There are no implicit conversions from other types to the `char` type. However, any [integral](integral-numeric-types.md) or [floating-point](floating-point-numeric-types.md) numeric type is explicitly convertible to `char`. +No implicit conversions exist from other types to the `char` type. However, you can explicitly convert any [integral](integral-numeric-types.md) or [floating-point](floating-point-numeric-types.md) numeric type to `char`. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/collections.md b/docs/csharp/language-reference/builtin-types/collections.md index 09180720ae441..8bc535f517a63 100644 --- a/docs/csharp/language-reference/builtin-types/collections.md +++ b/docs/csharp/language-reference/builtin-types/collections.md @@ -1,11 +1,11 @@ --- title: "Collections" description: Learn about collections in C#, which are used to work with groups of objects. Collections have different characteristics regarding adding and removing elements, modifying elements, and enumerating the collection elements. -ms.date: 02/04/2025 +ms.date: 01/14/2026 --- # Collections -The .NET runtime provides many collection types that store and manage groups of related objects. Some of the collection types, such as , , and are recognized [in the C# language](./built-in-types.md). In addition, interfaces like are recognized in the language for enumerating the elements of a collection. +The .NET runtime provides many collection types that store and manage groups of related objects. Some of the collection types, such as , , and , are recognized [in the C# language](./built-in-types.md). In addition, interfaces like are recognized in the language for enumerating the elements of a collection. Collections provide a flexible way to work with groups of objects. You can classify different collections by these characteristics: @@ -13,7 +13,7 @@ Collections provide a flexible way to work with groups of objects. You can class - **Performance profile**: Every collection has different performance profiles for actions like adding an element, finding an element, or removing an element. You can pick a collection type based on the operations used most in your app. - **Grow and shrink dynamically**: Most collections support adding or removing elements dynamically. Notably, , , and don't. -In addition to those characteristics, the runtime provides specialized collections that prevent adding or removing elements or modifying the elements of the collection. Other specialized collections provide safety for concurrent access in multi-threaded apps. +In addition to those characteristics, the runtime provides specialized collections that prevent adding or removing elements or modifying the elements of the collection. Other specialized collections provide safety for concurrent access in multithreaded apps. You can find all the collection types in the [.NET API reference](/dotnet/api/?term=collection). For more information, see [Commonly Used Collection Types](../../../standard/collections/commonly-used-collection-types.md) and [Selecting a Collection Class](../../../standard/collections/selecting-a-collection-class.md). @@ -24,11 +24,11 @@ You can find all the collection types in the [.NET API reference](/dotnet/api/?t is a [`ref struct`](./ref-struct.md) type that provides a snapshot over a sequence of elements without copying those elements. The compiler enforces safety rules to ensure the `Span` can't be accessed after the sequence it references is no longer in scope. It's used in many .NET APIs to improve performance. provides similar behavior when you can't use a `ref struct` type. -Beginning with C# 12, all of the collection types can be initialized using a [Collection expression](../operators/collection-expressions.md). +Beginning with C# 12, all of the collection types can be initialized by using a [Collection expression](../operators/collection-expressions.md). ## Indexable collections -An *indexable collection* is one where you can access each element using its index. Its *index* is the number of elements before it in the sequence. Therefore, the element reference by index `0` is the first element, index `1` is the second, and so on. These examples use the class. It's the most common indexable collection. +An *indexable collection* is a collection where you can access each element by using its index. An element's *index* is the number of elements before it in the sequence. Therefore, the element referenced by index `0` is the first element, index `1` is the second, and so on. These examples use the class. It's the most common indexable collection. The following example creates and initializes a list of strings, removes an element, and adds an element to the end of the list. After each modification, it iterates through the strings by using a [foreach](../statements/iteration-statements.md#the-foreach-statement) statement or a `for` loop: @@ -38,7 +38,7 @@ The following example removes elements from a list by index. Instead of a `forea :::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetRemoveItemByIndex"::: -For the type of elements in the , you can also define your own class. In the following example, the `Galaxy` class that is used by the is defined in the code. +For the type of elements in the , you can also define your own class. In the following example, the `Galaxy` class that the uses is defined in the code. :::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetCustomList"::: @@ -56,7 +56,7 @@ The following example uses the method to quickly find an item by key. +The following example uses the method to quickly find an item by key. :::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetFindInDictionary2"::: @@ -64,7 +64,7 @@ The following example instead uses the property is `false` and the property is undefined. That default value is also known as the *null* value of a nullable value type. | +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + ## Default value expressions Use the [`default` operator](../operators/default.md#default-operator) to produce the default value of a type, as the following example shows: @@ -44,10 +46,10 @@ var n = new System.Numerics.Complex(); Console.WriteLine(n); // output: (0, 0) ``` -At runtime, if the instance represents a value type, you can use the method to invoke the parameterless constructor to obtain the default value of the type. +At runtime, if the instance represents a value type, you can use the method to call the parameterless constructor and get the default value of the type. > [!NOTE] -> A [structure type](struct.md) (which is a value type) can have an [explicit parameterless constructor](struct.md#struct-initialization-and-default-values) that might produce a non-default value of the type. Thus, we recommend using the `default` operator or the `default` literal to produce the default value of a type. +> A [structure type](struct.md) (which is a value type) can have an [explicit parameterless constructor](struct.md#struct-initialization-and-default-values) that returns a non-default value of the type. To get the default value of a type, use the `default` operator or the `default` literal. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/enum.md b/docs/csharp/language-reference/builtin-types/enum.md index cd6c9f367ee8c..4c1f7e380d956 100644 --- a/docs/csharp/language-reference/builtin-types/enum.md +++ b/docs/csharp/language-reference/builtin-types/enum.md @@ -1,7 +1,7 @@ --- title: "Enumeration types" description: "Learn about C# enumeration types that represent a choice or a combination of choices" -ms.date: 11/24/2025 +ms.date: 01/14/2026 f1_keywords: - "enum" - "enum_CSharpKeyword" @@ -25,7 +25,7 @@ enum Season } ``` -By default, the associated constant values of enum members are of type `int`; they start with zero and increase by one following the definition text order. You can explicitly specify any other [integral numeric](integral-numeric-types.md) type as an underlying type of an enumeration type. You can also explicitly specify the associated constant values, as the following example shows: +By default, the associated constant values of enum members are of type `int`. They start with zero and increase by one following the definition text order. You can explicitly specify any other [integral numeric](integral-numeric-types.md) type as an underlying type of an enumeration type. You can also explicitly specify the associated constant values, as the following example shows: ```csharp enum ErrorCode : ushort @@ -49,17 +49,17 @@ C# allows implicit conversions from the literal value `0` to any enum type, and In the preceding example, both `port1` and `port2` are assigned the value `0`, but `GpioPort` has no member with that value. The method confirms these are invalid enum values. -This implicit conversion exists because the 0-bit pattern is the default for all struct types, including all enum types. However, it can introduce bugs in your code. To avoid these issues: +This implicit conversion exists because the 0-bit pattern is the default for all struct types, including all enum types. However, it can introduce bugs in your code. To avoid these problems: -- You should almost always define a member with value `0` in your enums. +- Almost always define a member with value `0` in your enums. - Use to validate enum values when converting from numeric types. - Be cautious when using numeric parameters that might be implicitly converted to enum types. -You use an enumeration type to represent a choice from a set of mutually exclusive values or a combination of choices. To represent a combination of choices, define an enumeration type as bit flags. +Use an enumeration type to represent a choice from a set of mutually exclusive values or a combination of choices. To represent a combination of choices, define an enumeration type as bit flags. ## Enumeration types as bit flags -If you want an enumeration type to represent a combination of choices, define enum members for those choices such that an individual choice is a bit field. That is, the associated values of those enum members should be the powers of two. Then, you can use the [bitwise logical operators `|` or `&`](../operators/bitwise-and-shift-operators.md#enumeration-logical-operators) to combine choices or intersect combinations of choices, respectively. To indicate that an enumeration type declares bit fields, apply the [Flags](xref:System.FlagsAttribute) attribute to it. As the following example shows, you can also include some typical combinations in the definition of an enumeration type. +If you want an enumeration type to represent a combination of choices, define enum members for those choices so that an individual choice is a bit field. That is, use the associated values of those enum members as the powers of two. Then, use the [bitwise logical operators `|` or `&`](../operators/bitwise-and-shift-operators.md#enumeration-logical-operators) to combine choices or intersect combinations of choices, respectively. To indicate that an enumeration type declares bit fields, apply the [Flags](xref:System.FlagsAttribute) attribute to it. As the following example shows, you can also include some typical combinations in the definition of an enumeration type. :::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetFlags"::: @@ -67,19 +67,19 @@ For more information and examples, see the type is the abstract base class of all enumeration types. It provides a number of methods to get information about an enumeration type and its values. For more information and examples, see the API reference page. +The type is the abstract base class of all enumeration types. It provides many methods to get information about an enumeration type and its values. For more information and examples, see the API reference page. You can use `System.Enum` in a base class constraint (that is known as the [enum constraint](../../programming-guide/generics/constraints-on-type-parameters.md#enum-constraints)) to specify that a type parameter is an enumeration type. Any enumeration type also satisfies the `struct` constraint, which is used to specify that a type parameter is a non-nullable value type. ## Conversions -For any enumeration type, there exist explicit conversions between the enumeration type and its underlying integral type. If you [cast](../operators/type-testing-and-cast.md#cast-expression) an enum value to its underlying type, the result is the associated integral value of an enum member. +For any enumeration type, explicit conversions exist between the enumeration type and its underlying integral type. If you [cast](../operators/type-testing-and-cast.md#cast-expression) an enum value to its underlying type, the result is the associated integral value of an enum member. :::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetConversions"::: -Use the method to determine whether an enumeration type contains an enum member with the certain associated value. +Use the method to determine whether an enumeration type contains an enum member with a certain associated value. -For any enumeration type, there exist [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the type, respectively. +For any enumeration type, [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the type exist, respectively. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/floating-point-numeric-types.md b/docs/csharp/language-reference/builtin-types/floating-point-numeric-types.md index de855a991bf1d..4aacbf6ddd42e 100644 --- a/docs/csharp/language-reference/builtin-types/floating-point-numeric-types.md +++ b/docs/csharp/language-reference/builtin-types/floating-point-numeric-types.md @@ -1,7 +1,7 @@ --- title: "Floating-point numeric types" description: "Learn about the built-in C# floating-point types: float, double, and decimal" -ms.date: 02/04/2021 +ms.date: 01/14/2026 f1_keywords: - "float" - "float_CSharpKeyword" @@ -21,7 +21,9 @@ helpviewer_keywords: --- # Floating-point numeric types (C# reference) -The *floating-point numeric types* represent real numbers. All floating-point numeric types are [value types](value-types.md). They are also [simple types](value-types.md#built-in-value-types) and can be initialized with [literals](#real-literals). All floating-point numeric types support [arithmetic](../operators/arithmetic-operators.md), [comparison](../operators/comparison-operators.md), and [equality](../operators/equality-operators.md) operators. +The *floating-point numeric types* represent real numbers. All floating-point numeric types are [value types](value-types.md). They're also [simple types](value-types.md#built-in-value-types), and you can initialize them by using [literals](#real-literals). All floating-point numeric types support [arithmetic](../operators/arithmetic-operators.md), [comparison](../operators/comparison-operators.md), and [equality](../operators/equality-operators.md) operators. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] ## Characteristics of the floating-point types @@ -33,7 +35,7 @@ C# supports the following predefined floating-point types: |`double`|±5.0 × 10−324 to ±1.7 × 10308|~15-17 digits|8 bytes|| |`decimal`|±1.0 x 10-28 to ±7.9228 x 1028|28-29 digits|16 bytes|| -In the preceding table, each C# type keyword from the leftmost column is an alias for the corresponding .NET type. They are interchangeable. For example, the following declarations declare variables of the same type: +In the preceding table, each C# type keyword from the leftmost column is an alias for the corresponding .NET type. They're interchangeable. For example, the following declarations declare variables of the same type: ```csharp double a = 12.3; @@ -42,16 +44,16 @@ System.Double b = 12.3; The default value of each floating-point type is zero, `0`. Each of the floating-point types has the `MinValue` and `MaxValue` constants that provide the minimum and maximum finite value of that type. The `float` and `double` types also provide constants that represent not-a-number and infinity values. For example, the `double` type provides the following constants: , , and . -The `decimal` type is appropriate when the required degree of precision is determined by the number of digits to the right of the decimal point. Such numbers are commonly used in financial applications, for currency amounts (for example, $1.00), interest rates (for example, 2.625%), and so forth. Even numbers that are precise to only one decimal digit are handled more accurately by the `decimal` type: 0.1, for example, can be exactly represented by a `decimal` instance, while there's no `double` or `float` instance that exactly represents 0.1. Because of this difference in numeric types, unexpected rounding errors can occur in arithmetic calculations when you use `double` or `float` for decimal data. You can use `double` instead of `decimal` when optimizing performance is more important than ensuring accuracy. However, any difference in performance would go unnoticed by all but the most calculation-intensive applications. Another possible reason to avoid `decimal` is to minimize storage requirements. For example, [ML.NET](../../../machine-learning/mldotnet-api.md) uses `float` because the difference between 4 bytes and 16 bytes adds up for very large data sets. For more information, see . +The `decimal` type is appropriate when the required degree of precision is determined by the number of digits to the right of the decimal point. Such numbers are commonly used in financial applications, for currency amounts (for example, $1.00), interest rates (for example, 2.625%), and so forth. Even numbers that are precise to only one decimal digit are handled more accurately by the `decimal` type: 0.1, for example, can be exactly represented by a `decimal` instance, while there's no `double` or `float` instance that exactly represents 0.1. Because of this difference in numeric types, unexpected rounding errors can occur in arithmetic calculations when you use `double` or `float` for decimal data. You can use `double` instead of `decimal` when optimizing performance is more important than ensuring accuracy. However, any difference in performance goes unnoticed by all but the most calculation-intensive applications. Another possible reason to avoid `decimal` is to minimize storage requirements. For example, [ML.NET](../../../machine-learning/mldotnet-api.md) uses `float` because the difference between 4 bytes and 16 bytes adds up for very large data sets. For more information, see . You can mix [integral](integral-numeric-types.md) types and the `float` and `double` types in an expression. In this case, integral types are implicitly converted to one of the floating-point types and, if necessary, the `float` type is implicitly converted to `double`. The expression is evaluated as follows: -- If there is `double` type in the expression, the expression evaluates to `double`, or to [`bool`](bool.md) in relational and equality comparisons. -- If there is no `double` type in the expression, the expression evaluates to `float`, or to `bool` in relational and equality comparisons. +- If there's a `double` type in the expression, the expression evaluates to `double`, or to [`bool`](bool.md) in relational and equality comparisons. +- If there's no `double` type in the expression, the expression evaluates to `float`, or to `bool` in relational and equality comparisons. You can also mix integral types and the `decimal` type in an expression. In this case, integral types are implicitly converted to the `decimal` type and the expression evaluates to `decimal`, or to `bool` in relational and equality comparisons. -You cannot mix the `decimal` type with the `float` and `double` types in an expression. In this case, if you want to perform arithmetic, comparison, or equality operations, you must explicitly convert the operands either from or to the `decimal` type, as the following example shows: +You can't mix the `decimal` type with the `float` and `double` types in an expression. In this case, if you want to perform arithmetic, comparison, or equality operations, you must explicitly convert the operands either from or to the `decimal` type, as the following example shows: ```csharp double a = 1.0; @@ -64,13 +66,13 @@ You can use either [standard numeric format strings](../../../standard/base-type ## Real literals -The type of a real literal is determined by its suffix as follows: +The suffix on a real literal determines its type: -- The literal without suffix or with the `d` or `D` suffix is of type `double` -- The literal with the `f` or `F` suffix is of type `float` -- The literal with the `m` or `M` suffix is of type `decimal` +- A literal without a suffix or with the `d` or `D` suffix is a `double`. +- A literal with the `f` or `F` suffix is a `float`. +- A literal with the `m` or `M` suffix is a `decimal`. -The following code demonstrates an example of each: +The following code shows an example of each type: ```csharp double d = 3D; @@ -86,7 +88,7 @@ myMoney = 400.75M; The preceding example also shows the use of `_` as a *digit separator*. You can use the digit separator with all kinds of numeric literals. -You can also use scientific notation, that is, specify an exponent part of a real literal, as the following example shows: +You can also use scientific notation, which specifies an exponent part of a real literal, as the following example shows: ```csharp double d = 0.42e2; @@ -101,7 +103,7 @@ Console.WriteLine(m); // output: 1500000 ## Conversions -There is only one implicit conversion between floating-point numeric types: from `float` to `double`. However, you can convert any floating-point type to any other floating-point type with the [explicit cast](../operators/type-testing-and-cast.md#cast-expression). For more information, see [Built-in numeric conversions](numeric-conversions.md). +There's only one implicit conversion between floating-point numeric types: from `float` to `double`. However, you can convert any floating-point type to any other floating-point type by using the [explicit cast](../operators/type-testing-and-cast.md#cast-expression). For more information, see [Built-in numeric conversions](numeric-conversions.md). ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/integral-numeric-types.md b/docs/csharp/language-reference/builtin-types/integral-numeric-types.md index 78e0076a5617f..0bf85aab45d63 100644 --- a/docs/csharp/language-reference/builtin-types/integral-numeric-types.md +++ b/docs/csharp/language-reference/builtin-types/integral-numeric-types.md @@ -2,7 +2,7 @@ title: "Integral numeric types" titleSuffix: "" description: "Learn the range, storage size, and uses for each of the integral numeric types." -ms.date: 11/18/2025 +ms.date: 01/14/2026 f1_keywords: - "byte_CSharpKeyword" - "sbyte_CSharpKeyword" @@ -32,7 +32,9 @@ helpviewer_keywords: --- # Integral numeric types (C# reference) -The *integral numeric types* represent integer numbers. All integral numeric types are [value types](value-types.md). The integral types are [simple types](value-types.md#built-in-value-types) and can be initialized with [literals](#integer-literals). All integral numeric types support [arithmetic](../operators/arithmetic-operators.md), [bitwise logical](../operators/bitwise-and-shift-operators.md), [comparison](../operators/comparison-operators.md), and [equality](../operators/equality-operators.md) operators. +The *integral numeric types* represent integer numbers. All integral numeric types are [value types](value-types.md). The integral types are [simple types](value-types.md#built-in-value-types) and you initialize them with [literals](#integer-literals). All integral numeric types support [arithmetic](../operators/arithmetic-operators.md), [bitwise logical](../operators/bitwise-and-shift-operators.md), [comparison](../operators/comparison-operators.md), and [equality](../operators/equality-operators.md) operators. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] ## Characteristics of the integral types @@ -58,7 +60,7 @@ int a = 123; System.Int32 b = 123; ``` -The `nint` and `nuint` types in the last two rows of the table are native-sized integers. You can use the `nint` and `nuint` contextual keywords to define *native-sized integers*. Native-sized integers are 32-bit integers when running in a 32-bit process, or 64-bit integers when running in a 64-bit process. They can be used for interop scenarios, low-level libraries, and to optimize performance in scenarios where integer math is used extensively. +The `nint` and `nuint` types in the last two rows of the table are native-sized integers. You can use the `nint` and `nuint` contextual keywords to define *native-sized integers*. Native-sized integers are 32-bit integers when running in a 32-bit process, or 64-bit integers when running in a 64-bit process. Use them for interop scenarios, low-level libraries, and to optimize performance in scenarios where integer math is used extensively. The native-sized integer types are represented internally as the .NET types and . The `nint` and `nuint` types are aliases for the underlying types. @@ -70,7 +72,7 @@ Use the structure ## Integer literals -Integer literals can be +Integer literals can be: - *decimal*: without any prefix - *hexadecimal*: with the `0x` or `0X` prefix @@ -88,22 +90,22 @@ The preceding example also shows the use of `_` as a *digit separator*. You can The suffix determines the type of an integer literal as follows: -- If the literal has no suffix, its type is the first of the following types in which its value can be represented: `int`, `uint`, `long`, `ulong`. +- If the literal has no suffix, the compiler assigns the type as the first of the following types in which its value can be represented: `int`, `uint`, `long`, `ulong`. > [!NOTE] - > Literals are interpreted as positive values. For example, the literal `0xFF_FF_FF_FF` represents the number `4294967295` of the `uint` type, though it has the same bit representation as the number `-1` of the `int` type. If you need a value of a certain type, cast a literal to that type. Use the `unchecked` operator, if a literal value can't be represented in the target type. For example, `unchecked((int)0xFF_FF_FF_FF)` produces `-1`. + > The compiler interprets literals as positive values. For example, the literal `0xFF_FF_FF_FF` represents the number `4,294,967,295` of the `uint` type, though it has the same bit representation as the number `-1` of the `int` type. If you need a value of a certain type, cast a literal to that type. Use the `unchecked` operator if a literal value can't be represented in the target type. For example, `unchecked((int)0xFF_FF_FF_FF)` produces `-1`. -- If the literal includes the `U` or `u` suffix, its type is the first of the following types in which its value can be represented: `uint`, `ulong`. -- If the literal includes the `L` or `l` suffix, its type is the first of the following types in which its value can be represented: `long`, `ulong`. +- If the literal includes the `U` or `u` suffix, the compiler assigns the type as the first of the following types in which its value can be represented: `uint`, `ulong`. +- If the literal includes the `L` or `l` suffix, the compiler assigns the type as the first of the following types in which its value can be represented: `long`, `ulong`. > [!NOTE] > You can use the lowercase letter `l` as a suffix. However, `l` generates a compiler warning because the letter `l` can be confused with the digit `1`. Use `L` for clarity. -- If the literal includes one of the `UL`, `Ul`, `uL`, `ul`, `LU`, `Lu`, `lU`, or `lu` suffixes, its type is `ulong`. +- If the literal includes one of the `UL`, `Ul`, `uL`, `ul`, `LU`, `Lu`, `lU`, or `lu` suffixes, the compiler assigns the type as `ulong`. If the value represented by an integer literal exceeds , a compiler error [CS1021](../../misc/cs1021.md) occurs. -If the determined type of an integer literal is `int` and the value represented by the literal is within the range of the destination type, the value can be implicitly converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, `nint`, or `nuint`: +If the compiler determines the type of an integer literal as `int` and the value represented by the literal is within the range of the destination type, the value can be implicitly converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, `nint`, or `nuint`: ```csharp byte a = 17; @@ -121,13 +123,13 @@ var longVariable = (long)42; ## Conversions -You can convert any integral numeric type to any other integral numeric type. If the destination type can store all values of the source type, the conversion is implicit. Otherwise, you need to use a [cast expression](../operators/type-testing-and-cast.md#cast-expression) to perform an explicit conversion. For more information, see [Built-in numeric conversions](numeric-conversions.md). +You can convert any integral numeric type to any other integral numeric type. If the destination type can store all values of the source type, the conversion is implicit. Otherwise, use a [cast expression](../operators/type-testing-and-cast.md#cast-expression) to perform an explicit conversion. For more information, see [Built-in numeric conversions](numeric-conversions.md). ## Native sized integers Native sized integer types have special behavior because the storage matches the natural integer size on the target machine. -- To get the size of a native-sized integer at run time, you can use `sizeof()`. However, the code must be compiled in an unsafe context. For example: +- To get the size of a native-sized integer at run time, use `sizeof()`. However, the code must be compiled in an unsafe context. For example: :::code language="csharp" source="snippets/shared/NativeIntegerTypes.cs" id="SizeOf"::: @@ -140,7 +142,7 @@ Native sized integer types have special behavior because the storage matches the - For `nint`: to . - For `nuint`: to . - The compiler provides implicit and explicit conversions to other numeric types. For more information, see [Built-in numeric conversions](numeric-conversions.md). -- There's no direct syntax for native-sized integer literals. There's no suffix to indicate that a literal is a native-sized integer, such as `L` to indicate a `long`. You can use implicit or explicit casts of other integer values instead. For example: +- There's no direct syntax for native-sized integer literals. There's no suffix to indicate that a literal is a native-sized integer, such as `L` to indicate a `long`. Use implicit or explicit casts of other integer values instead. For example: ```csharp nint a = 42 diff --git a/docs/csharp/language-reference/builtin-types/nullable-reference-types.md b/docs/csharp/language-reference/builtin-types/nullable-reference-types.md index 2d50ada7bfccc..26d12f4331094 100644 --- a/docs/csharp/language-reference/builtin-types/nullable-reference-types.md +++ b/docs/csharp/language-reference/builtin-types/nullable-reference-types.md @@ -1,29 +1,31 @@ --- title: "Nullable reference types" description: Learn about C# nullable reference types and how to use them -ms.date: 11/22/2024 +ms.date: 01/14/2026 --- # Nullable reference types (C# reference) > [!NOTE] > This article covers nullable reference types. You can also declare [nullable value types](nullable-value-types.md). -Nullable reference types are available in code that's in a *nullable aware context*. Nullable reference types, the null static analysis warnings, and the [null-forgiving operator](../operators/null-forgiving.md) are optional language features. All are turned off by default. A *nullable context* is controlled at the project level using build settings, or in code using pragmas. +You can use nullable reference types in code that's in a *nullable aware context*. Nullable reference types, the null static analysis warnings, and the [null-forgiving operator](../operators/null-forgiving.md) are optional language features. All are turned off by default. You control a *nullable context* at the project level by using build settings, or in code by using pragmas. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] > [!IMPORTANT] > All project templates enable the *nullable context* for the project. Projects created with earlier templates don't include this element, and these features are off unless you enable them in the project file or use pragmas. - In a nullable aware context: +In a nullable aware context: -- A variable of a reference type `T` must be initialized with non-null, and can never be assigned a value that might be `null`. -- A variable of a reference type `T?` can be initialized with `null` or assigned `null`, but is required to be checked against `null` before dereferencing. -- A variable `m` of type `T?` is considered to be non-null when you apply the null-forgiving operator, as in `m!`. +- You must initialize a variable of a reference type `T` with a non-null value, and you can never assign a value that might be `null`. +- You can initialize a variable of a reference type `T?` with `null` or assign `null`, but you must check it against `null` before dereferencing. +- When you apply the null-forgiving operator to a variable `m` of type `T?`, as in `m!`, the variable is considered to be non-null. -The compiler enforces the distinctions between a non-nullable reference type `T` and a nullable reference type `T?` using the preceding rules. A variable of type `T` and a variable of type `T?` are the same .NET type. The following example declares a non-nullable string and a nullable string, and then uses the null-forgiving operator to assign a value to a non-nullable string: +The compiler enforces the distinctions between a non-nullable reference type `T` and a nullable reference type `T?` by using the preceding rules. A variable of type `T` and a variable of type `T?` are the same .NET type. The following example declares a non-nullable string and a nullable string, and then uses the null-forgiving operator to assign a value to a non-nullable string: :::code language="csharp" source="snippets/shared/NullableReferenceTypes.cs" id="SnippetCoreSyntax"::: -The variables `notNull` and `nullable` are both represented by the type. Because the non-nullable and nullable types are both stored as the same type, there are several locations where using a nullable reference type isn't allowed. In general, a nullable reference type can't be used as a base class or implemented interface. A nullable reference type can't be used in any object creation or type testing expression. A nullable reference type can't be the type of a member access expression. The following examples show these constructs: +The variables `notNull` and `nullable` both use the type. Because the non-nullable and nullable types both use the same type, you can't use a nullable reference type in several locations. In general, you can't use a nullable reference type as a base class or implemented interface. You can't use a nullable reference type in any object creation or type testing expression. You can't use a nullable reference type as the type of a member access expression. The following examples show these constructs: ```csharp public MyClass : System.Object? // not allowed @@ -47,16 +49,16 @@ try The examples in the previous section illustrate the nature of nullable reference types. Nullable reference types aren't new class types, but rather annotations on existing reference types. The compiler uses those annotations to help you find potential null reference errors in your code. There's no runtime difference between a non-nullable reference type and a nullable reference type. The compiler doesn't add any runtime checking for non-nullable reference types. The benefits are in the compile-time analysis. The compiler generates warnings that help you find and fix potential null errors in your code. You declare your intent, and the compiler warns you when your code violates that intent. > [!IMPORTANT] -> Nullable reference annotations don't introduce behavior changes, but other libraries may use reflection to produce different runtime behavior for nullable and non-nullable reference types. Notably, Entity Framework Core reads nullable attributes. It interprets a nullable reference as an optional value, and a non-nullable reference as a required value. +> Nullable reference annotations don't introduce behavior changes, but other libraries might use reflection to produce different runtime behavior for nullable and non-nullable reference types. Notably, Entity Framework Core reads nullable attributes. It interprets a nullable reference as an optional value, and a non-nullable reference as a required value. In a nullable enabled context, the compiler performs static analysis on variables of any reference type, both nullable and non-nullable. The compiler tracks the *null-state* of each reference variable as either *not-null* or *maybe-null*. The default state of a non-nullable reference is *not-null*. The default state of a nullable reference is *maybe-null*. -Non-nullable reference types should always be safe to dereference because their *null-state* is *not-null*. To enforce that rule, the compiler issues warnings if a non-nullable reference type isn't initialized to a non-null value. Local variables must be assigned where they're declared. Every field must be assigned a *not-null* value, in a field initializer or every constructor. The compiler issues warnings when a non-nullable reference is assigned to a reference whose state is *maybe-null*. Generally, a non-nullable reference is *not-null* and no warnings are issued when those variables are dereferenced. +Non-nullable reference types should always be safe to dereference because their *null-state* is *not-null*. To enforce that rule, the compiler issues warnings if a non-nullable reference type isn't initialized to a non-null value. You must assign local variables where you declare them. Every field must be assigned a *not-null* value, in a field initializer or every constructor. The compiler issues warnings when a non-nullable reference is assigned to a reference whose state is *maybe-null*. Generally, a non-nullable reference is *not-null* and no warnings are issued when you dereference those variables. > [!NOTE] > If you assign a *maybe-null* expression to a non-nullable reference type, the compiler generates a warning. The compiler then generates warnings for that variable until it's assigned to a *not-null* expression. -Nullable reference types can be initialized or assigned to `null`. Therefore, static analysis must determine that a variable is *not-null* before it's dereferenced. If a nullable reference is determined to be *maybe-null*, assigning to a non-nullable reference variable generates a compiler warning. The following class shows examples of these warnings: +You can initialize or assign `null` to nullable reference types. Therefore, static analysis must determine that a variable is *not-null* before it's dereferenced. If a nullable reference is determined to be *maybe-null*, assigning it to a non-nullable reference variable generates a compiler warning. The following class shows examples of these warnings: :::code language="csharp" source="snippets/shared/NullableReferenceTypes.cs" id="SnippetClassWithNullable"::: @@ -64,15 +66,15 @@ The following snippet shows where the compiler emits warnings when using this cl :::code language="csharp" source="snippets/shared/NullableReferenceTypes.cs" id="SnippetLocalWarnings"::: -The preceding examples demonstrate how compiler's static analysis determines the *null-state* of reference variables. The compiler applies language rules for null checks and assignments to inform its analysis. The compiler can't make assumptions about the semantics of methods or properties. If you call methods that perform null checks, the compiler can't know those methods affect a variable's *null-state*. There are attributes you can add to your APIs to inform the compiler about the semantics of arguments and return values. Many common APIs in the .NET libraries have these attributes. For example, the compiler correctly interprets as a null check. For more information about the attributes that apply to *null-state* static analysis, see the article on [Nullable attributes](../attributes/nullable-analysis.md). +The preceding examples demonstrate how compiler's static analysis determines the *null-state* of reference variables. The compiler applies language rules for null checks and assignments to inform its analysis. The compiler can't make assumptions about the semantics of methods or properties. If you call methods that perform null checks, the compiler can't know those methods affect a variable's *null-state*. You can add attributes to your APIs to inform the compiler about the semantics of arguments and return values. Many common APIs in the .NET libraries have these attributes. For example, the compiler correctly interprets as a null check. For more information about the attributes that apply to *null-state* static analysis, see the article on [Nullable attributes](../attributes/nullable-analysis.md). ## Setting the nullable context -There are two ways to control the nullable context. At the project level, you can add the `enable` project setting. In a single C# source file, you can add the `#nullable enable` pragma to enable the nullable context. See the article on [setting a nullable strategy](../../nullable-migration-strategies.md). Before .NET 6, new projects use the default, `disable`. Beginning with .NET 6, new projects include the `enable` element in the project file. +You can control the nullable context in two ways. At the project level, add the `enable` project setting. In a single C# source file, add the `#nullable enable` pragma to enable the nullable context. See the article on [setting a nullable strategy](../../nullable-migration-strategies.md). Before .NET 6, new projects use the default, `disable`. Beginning with .NET 6, new projects include the `enable` element in the project file. ## C# language specification -For more information, see the [Nullable reference types](~/_csharpstandard/standard/types.md#89-reference-types-and-nullability) section of the [C# language specification](~/_csharpstandard/standard/README.md): +For more information, see the [Nullable reference types](~/_csharpstandard/standard/types.md#89-reference-types-and-nullability) section of the [C# language specification](~/_csharpstandard/standard/README.md). ## See also diff --git a/docs/csharp/language-reference/builtin-types/nullable-value-types.md b/docs/csharp/language-reference/builtin-types/nullable-value-types.md index 75d81e92f5a15..32191ec7f797f 100644 --- a/docs/csharp/language-reference/builtin-types/nullable-value-types.md +++ b/docs/csharp/language-reference/builtin-types/nullable-value-types.md @@ -1,57 +1,59 @@ --- title: "Nullable value types" description: Learn about C# nullable value types and how to use them -ms.date: 11/04/2019 +ms.date: 01/14/2026 helpviewer_keywords: - "nullable value types [C#]" --- # Nullable value types (C# reference) -A *nullable value type* `T?` represents all values of its underlying [value type](value-types.md) `T` and an additional [null](../keywords/null.md) value. For example, you can assign any of the following three values to a `bool?` variable: `true`, `false`, or `null`. An underlying value type `T` cannot be a nullable value type itself. +A *nullable value type* `T?` represents all values of its underlying [value type](value-types.md) `T` and an additional [null](../keywords/null.md) value. For example, you can assign any of the following three values to a `bool?` variable: `true`, `false`, or `null`. An underlying value type `T` can't be a nullable value type itself. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] Any nullable value type is an instance of the generic structure. You can refer to a nullable value type with an underlying type `T` in any of the following interchangeable forms: `Nullable` or `T?`. -You typically use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or `bool`, variable can only be either `true` or `false`. However, in some applications a variable value can be undefined or missing. For example, a database field may contain `true` or `false`, or it may contain no value at all, that is, `NULL`. You can use the `bool?` type in that scenario. +Typically, use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or `bool`, variable can only be either `true` or `false`. However, in some applications a variable value can be undefined or missing. For example, a database field may contain `true` or `false`, or it might contain no value at all, that is, `NULL`. You can use the `bool?` type in that scenario. ## Declaration and assignment -As a value type is implicitly convertible to the corresponding nullable value type, you can assign a value to a variable of a nullable value type as you would do that for its underlying value type. You can also assign the `null` value. For example: +Because a value type is implicitly convertible to the corresponding nullable value type, you can assign a value to a variable of a nullable value type as you do that for its underlying value type. You can also assign the `null` value. For example: -[!code-csharp[declare and assign](snippets/shared/NullableValueTypes.cs#Declaration)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="Declaration"::: -The default value of a nullable value type represents `null`, that is, it's an instance whose property returns `false`. +The default value of a nullable value type represents `null`. It's an instance whose property returns `false`. ## Examination of an instance of a nullable value type -You can use the [`is` operator with a type pattern](../operators/type-testing-and-cast.md#type-testing-with-pattern-matching) to both examine an instance of a nullable value type for `null` and retrieve a value of an underlying type: +To check an instance of a nullable value type for `null` and get a value of an underlying type, use the [`is` operator with a type pattern](../operators/type-testing-and-cast.md#type-testing-with-pattern-matching): -[!code-csharp[use pattern matching](snippets/shared/NullableValueTypes.cs#PatternMatching)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="PatternMatching"::: -You always can use the following read-only properties to examine and get a value of a nullable value type variable: +You can always use the following read-only properties to check and get a value of a nullable value type variable: -- indicates whether an instance of a nullable value type has a value of its underlying type. +- shows whether an instance of a nullable value type has a value of its underlying type. - gets the value of an underlying type if is `true`. If is `false`, the property throws an . -The following example uses the `HasValue` property to test whether the variable contains a value before displaying it: +The following example uses the `HasValue` property to check whether the variable contains a value before displaying it: -[!code-csharp[use HasValue](snippets/shared/NullableValueTypes.cs#HasValue)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="HasValue"::: You can also compare a variable of a nullable value type with `null` instead of using the `HasValue` property, as the following example shows: -[!code-csharp[use comparison with null](snippets/shared/NullableValueTypes.cs#CompareWithNull)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="CompareWithNull"::: ## Conversion from a nullable value type to an underlying type -If you want to assign a value of a nullable value type to a non-nullable value type variable, you might need to specify the value to be assigned in place of `null`. Use the [null-coalescing operator `??`](../operators/null-coalescing-operator.md) to do that (you can also use the method for the same purpose): +If you want to assign a value of a nullable value type to a non-nullable value type variable, you might need to specify the value to assign in place of `null`. Use the [null-coalescing operator `??`](../operators/null-coalescing-operator.md) to do that. You can also use the method for the same purpose: -[!code-csharp[?? operator](snippets/shared/NullableValueTypes.cs#NullCoalescing)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="NullCoalescing"::: If you want to use the [default](default-values.md) value of the underlying value type in place of `null`, use the method. You can also explicitly cast a nullable value type to a non-nullable type, as the following example shows: -[!code-csharp[explicit cast](snippets/shared/NullableValueTypes.cs#Cast)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="Cast"::: At run time, if the value of a nullable value type is `null`, the explicit cast throws an . @@ -59,57 +61,57 @@ A non-nullable value type `T` is implicitly convertible to the corresponding nul ## Lifted operators -The predefined unary and binary [operators](../operators/index.md) or any overloaded operators that are supported by a value type `T` are also supported by the corresponding nullable value type `T?`. These operators, also known as *lifted operators*, produce `null` if one or both operands are `null`; otherwise, the operator uses the contained values of its operands to calculate the result. For example: +A nullable value type `T?` supports the predefined unary and binary [operators](../operators/index.md) or any overloaded operators that a value type `T` supports. These operators, also known as *lifted operators*, return `null` if one or both operands are `null`. Otherwise, the operator uses the contained values of its operands to calculate the result. For example: -[!code-csharp[lifted operators](snippets/shared/NullableValueTypes.cs#LiftedOperator)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="LiftedOperator"::: > [!NOTE] > For the `bool?` type, the predefined `&` and `|` operators don't follow the rules described in this section: the result of an operator evaluation can be non-null even if one of the operands is `null`. For more information, see the [Nullable Boolean logical operators](../operators/boolean-logical-operators.md#nullable-boolean-logical-operators) section of the [Boolean logical operators](../operators/boolean-logical-operators.md) article. -For the [comparison operators](../operators/comparison-operators.md) `<`, `>`, `<=`, and `>=`, if one or both operands are `null`, the result is `false`; otherwise, the contained values of operands are compared. Do not assume that because a particular comparison (for example, `<=`) returns `false`, the opposite comparison (`>`) returns `true`. The following example shows that 10 is +For the [comparison operators](../operators/comparison-operators.md) `<`, `>`, `<=`, and `>=`, if one or both operands are `null`, the result is `false`. Otherwise, the contained values of operands are compared. Don't assume that because a particular comparison (for example, `<=`) returns `false`, the opposite comparison (`>`) returns `true`. The following example shows that 10 is - neither greater than or equal to `null` - nor less than `null` -[!code-csharp[relational and equality operators](snippets/shared/NullableValueTypes.cs#ComparisonOperators)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="ComparisonOperators"::: -For the [equality operator](../operators/equality-operators.md#equality-operator-) `==`, if both operands are `null`, the result is `true`, if only one of the operands is `null`, the result is `false`; otherwise, the contained values of operands are compared. +For the [equality operator](../operators/equality-operators.md#equality-operator-) `==`, if both operands are `null`, the result is `true`. If only one of the operands is `null`, the result is `false`. Otherwise, the contained values of operands are compared. -For the [inequality operator](../operators/equality-operators.md#inequality-operator-) `!=`, if both operands are `null`, the result is `false`, if only one of the operands is `null`, the result is `true`; otherwise, the contained values of operands are compared. +For the [inequality operator](../operators/equality-operators.md#inequality-operator-) `!=`, if both operands are `null`, the result is `false`. If only one of the operands is `null`, the result is `true`. Otherwise, the contained values of operands are compared. -If there exists a [user-defined conversion](../operators/user-defined-conversion-operators.md) between two value types, the same conversion can also be used between the corresponding nullable value types. +If a [user-defined conversion](../operators/user-defined-conversion-operators.md) exists between two value types, the same conversion can also be used between the corresponding nullable value types. ## Boxing and unboxing -An instance of a nullable value type `T?` is [boxed](../../programming-guide/types/boxing-and-unboxing.md) as follows: +The following rules apply when you [box](../../programming-guide/types/boxing-and-unboxing.md) an instance of a nullable value type `T?`: -- If returns `false`, the null reference is produced. -- If returns `true`, the corresponding value of the underlying value type `T` is boxed, not the instance of . +- If returns `false`, the boxing operation returns the null reference. +- If returns `true`, the boxing operation boxes the corresponding value of the underlying value type `T`, not the instance of . You can unbox a boxed value of a value type `T` to the corresponding nullable value type `T?`, as the following example shows: -[!code-csharp[boxing and unboxing](snippets/shared/NullableValueTypes.cs#Boxing)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="Boxing"::: ## How to identify a nullable value type The following example shows how to determine whether a instance represents a constructed nullable value type, that is, the type with a specified type parameter `T`: -[!code-csharp[whether Type is nullable](snippets/shared/NullableValueTypes.cs#IsTypeNullable)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="IsTypeNullable"::: As the example shows, you use the [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator to create a instance. -If you want to determine whether an instance is of a nullable value type, don't use the method to get a instance to be tested with the preceding code. When you call the method on an instance of a nullable value type, the instance is [boxed](#boxing-and-unboxing) to . As boxing of a non-null instance of a nullable value type is equivalent to boxing of a value of the underlying type, returns a instance that represents the underlying type of a nullable value type: +If you want to determine whether an instance is of a nullable value type, don't use the method to get a instance to test by using the preceding code. When you call the method on an instance of a nullable value type, the instance is [boxed](#boxing-and-unboxing) to . Because boxing a non-null instance of a nullable value type is equivalent to boxing a value of the underlying type, returns a instance that represents the underlying type of a nullable value type: -[!code-csharp[GetType example](snippets/shared/NullableValueTypes.cs#GetType)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="GetType"::: -Also, don't use the [is](../operators/type-testing-and-cast.md#the-is-operator) operator to determine whether an instance is of a nullable value type. As the following example shows, you cannot distinguish types of a nullable value type instance and its underlying type instance with the `is` operator: +Also, don't use the [is](../operators/type-testing-and-cast.md#the-is-operator) operator to determine whether an instance is of a nullable value type. As the following example shows, you can't distinguish types of a nullable value type instance and its underlying type instance by using the `is` operator: -[!code-csharp[is operator example](snippets/shared/NullableValueTypes.cs#IsOperator)] +:::code language="csharp" source="snippets/shared/NullableValueTypes.cs" id="IsOperator"::: -Instead use the from the first example and [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator to check if an instance is of a nullable value type. +Instead, use the method from the first example and the [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator to check if an instance is of a nullable value type. > [!NOTE] -> The methods described in this section are not applicable in the case of [nullable reference types](nullable-reference-types.md). +> The methods described in this section don't apply to [nullable reference types](nullable-reference-types.md). ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/numeric-conversions.md b/docs/csharp/language-reference/builtin-types/numeric-conversions.md index 0651fe15a6349..0ae8bdca0297d 100644 --- a/docs/csharp/language-reference/builtin-types/numeric-conversions.md +++ b/docs/csharp/language-reference/builtin-types/numeric-conversions.md @@ -1,7 +1,7 @@ --- description: Learn about the implicit and explicit conversions between the built-in numeric types in C# title: "Built-in numeric conversions" -ms.date: 01/30/2023 +ms.date: 01/14/2026 helpviewer_keywords: - "implicit numeric conversions [C#]" - "explicit numeric conversion [C#]" @@ -12,65 +12,64 @@ helpviewer_keywords: --- # Built-in numeric conversions (C# reference) -C# provides a set of [integral](integral-numeric-types.md) and [floating-point](floating-point-numeric-types.md) numeric types. There exists a conversion between any two numeric types, either implicit or explicit. You must use a [cast expression](../operators/type-testing-and-cast.md#cast-expression) to perform an explicit conversion. +C# provides a set of [integral](integral-numeric-types.md) and [floating-point](floating-point-numeric-types.md) numeric types. An implicit or explicit conversion exists between any two numeric types. Use a [cast expression](../operators/type-testing-and-cast.md#cast-expression) to perform an explicit conversion. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] ## Implicit numeric conversions The following table shows the predefined implicit conversions between the built-in numeric types: -|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`, or `decimal`, or `nint`| -|[ushort](integral-numeric-types.md)|`int`, `uint`, `long`, `ulong`, `float`, `double`, or `decimal`, `nint`, or `nuint`| -|[int](integral-numeric-types.md)|`long`, `float`, `double`, or `decimal`, `nint`| -|[uint](integral-numeric-types.md)|`long`, `ulong`, `float`, `double`, or `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`| +| 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` | > [!NOTE] -> The implicit conversions from `int`, `uint`, `long`, `ulong`, `nint`, or `nuint` to `float` and from `long`, `ulong`, `nint`, or `nuint` to `double` may cause a loss of precision, but never a loss of an order of magnitude. The other implicit numeric conversions never lose any information. +> 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. Also note that - Any [integral numeric type](integral-numeric-types.md) is implicitly convertible to any [floating-point numeric type](floating-point-numeric-types.md). - - There are no implicit conversions to the `byte` and `sbyte` types. There are no implicit conversions from the `double` and `decimal` types. - - There are no implicit conversions between the `decimal` type and the `float` or `double` types. - -- A value of a constant expression of type `int` (for example, a value represented by an integer literal) can be implicitly converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, `nint`, or `nuint`, if it's within the range of the destination type: +- A value of a constant expression of type `int` (for example, a value represented by an integer literal) can be implicitly converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, `nint`, or `nuint` if it's within the range of the destination type: ```csharp byte a = 13; byte b = 300; // CS0031: Constant value '300' cannot be converted to a 'byte' ``` - As the preceding example shows, if the constant value is not within the range of the destination type, a compiler error [CS0031](../../misc/cs0031.md) occurs. +If the constant value isn't within the range of the destination type, a compiler error [CS0031](../../misc/cs0031.md) occurs. ## Explicit numeric conversions -The following table shows the predefined explicit conversions between the built-in numeric types for which there is no [implicit conversion](#implicit-numeric-conversions): - -|From|To| -|----------|--------| -|[sbyte](integral-numeric-types.md)|`byte`, `ushort`, `uint`, `ulong`, or `nuint`| -|[byte](integral-numeric-types.md)|`sbyte`| -|[short](integral-numeric-types.md)|`sbyte`, `byte`, `ushort`, `uint`, `ulong`, or `nuint`| -|[ushort](integral-numeric-types.md)|`sbyte`, `byte`, or `short`| -|[int](integral-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, or `nuint`| -|[uint](integral-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, or `nint`| -|[long](integral-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `ulong`, `nint`, or `nuint`| -|[ulong](integral-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `nint`, or `nuint`| -|[float](floating-point-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `decimal`, `nint`, or `nuint`| -|[double](floating-point-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `decimal`, `nint`, or `nuint`| -|[decimal](floating-point-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `nint`, or `nuint`| -|[nint](integral-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `ulong`, or `nuint`| -|[nuint](integral-numeric-types.md)|`sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, or `nint`| +The following table shows the predefined explicit conversions between the built-in numeric types for which there's no [implicit conversion](#implicit-numeric-conversions): + +| From | To | +|--------------------------------------------|--------| +| [sbyte](integral-numeric-types.md) | `byte`, `ushort`, `uint`, `ulong`, or `nuint` | +| [byte](integral-numeric-types.md) | `sbyte` | +| [short](integral-numeric-types.md) | `sbyte`, `byte`, `ushort`, `uint`, `ulong`, or `nuint` | +| [ushort](integral-numeric-types.md) | `sbyte`, `byte`, or `short` | +| [int](integral-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, or `nuint` | +| [uint](integral-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, or `nint` | +| [long](integral-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `ulong`, `nint`, or `nuint` | +| [ulong](integral-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `nint`, or `nuint` | +| [float](floating-point-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `decimal`, `nint`, or `nuint` | +| [double](floating-point-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `decimal`, `nint`, or `nuint` | +| [decimal](floating-point-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `nint`, or `nuint` | +| [nint](integral-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `ulong`, or `nuint` | +| [nuint](integral-numeric-types.md) | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, or `nint` | > [!NOTE] > An explicit numeric conversion might result in data loss or throw an exception, typically an . @@ -78,25 +77,18 @@ The following table shows the predefined explicit conversions between the built- Also note that: - When you convert a value of an integral type to another integral type, the result depends on the [overflow-checking context](../statements/checked-and-unchecked.md). In a checked context, the conversion succeeds if the source value is within the range of the destination type. Otherwise, an is thrown. In an unchecked context, the conversion always succeeds, and proceeds as follows: - - If the source type is larger than the destination type, then the source value is truncated by discarding its "extra" most significant bits. The result is then treated as a value of the destination type. - - If the source type is smaller than the destination type, then the source value is either sign-extended or zero-extended so that it's of the same size as the destination type. Sign-extension is used if the source type is signed; zero-extension is used if the source type is unsigned. The result is then treated as a value of the destination type. - - If the source type is the same size as the destination type, then the source value is treated as a value of the destination type. -- When you convert a `decimal` value to an integral type, this value is rounded towards zero to the nearest integral value. If the resulting integral value is outside the range of the destination type, an is thrown. +- When you convert a `decimal` value to an integral type, this value is rounded toward zero to the nearest integral value. If the resulting integral value is outside the range of the destination type, an is thrown. -- When you convert a `double` or `float` value to an integral type, this value is rounded towards zero to the nearest integral value. If the resulting integral value is outside the range of the destination type, the result depends on the [overflow-checking context](../statements/checked-and-unchecked.md). In a checked context, an is thrown, while in an unchecked context, the result is an unspecified value of the destination type. +- When you convert a `double` or `float` value to an integral type, this value is rounded toward zero to the nearest integral value. If the resulting integral value is outside the range of the destination type, the result depends on the [overflow-checking context](../statements/checked-and-unchecked.md). In a checked context, an is thrown, while in an unchecked context, the result is an unspecified value of the destination type. - When you convert `double` to `float`, the `double` value is rounded to the nearest `float` value. If the `double` value is too small or too large to fit into the `float` type, the result is zero or infinity. - - When you convert `float` or `double` to `decimal`, the source value is converted to `decimal` representation and rounded to the nearest number after the 28th decimal place if necessary. Depending on the value of the source value, one of the following results may occur: - - If the source value is too small to be represented as a `decimal`, the result becomes zero. - - If the source value is NaN (not a number), infinity, or too large to be represented as a `decimal`, an is thrown. - - When you convert `decimal` to `float` or `double`, the source value is rounded to the nearest `float` or `double` value, respectively. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/record.md b/docs/csharp/language-reference/builtin-types/record.md index 313b5c3076e1e..4474e6b353af0 100644 --- a/docs/csharp/language-reference/builtin-types/record.md +++ b/docs/csharp/language-reference/builtin-types/record.md @@ -1,7 +1,7 @@ --- title: "Records" description: Learn about the record modifier for class and struct types in C#. Records provide standard support for value based equality on instances of record types. -ms.date: 12/16/2025 +ms.date: 01/14/2026 f1_keywords: - "record_CSharpKeyword" helpviewer_keywords: @@ -12,6 +12,8 @@ helpviewer_keywords: The `record` modifier provides built-in functionality for encapsulating data. The `record class` and `record` syntax define [reference types](reference-types.md). The `record struct` syntax defines a [value type](value-types.md). +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + When you declare a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) on a record, the compiler generates public properties for the primary constructor parameters. The primary constructor parameters to a record are *positional parameters*. The compiler creates *positional properties* that mirror the primary constructor or positional parameters. The compiler doesn't synthesize properties for primary constructor parameters on types that don't have the `record` modifier. The following two examples demonstrate `record` (or `record class`) reference types: diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 6980dca043b51..62e5ed82b69d0 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -1,21 +1,23 @@ --- title: "ref struct types" description: Learn about the ref struct type in C# -ms.date: 11/18/2025 +ms.date: 01/14/2026 --- # `ref` structure types (C# reference) -You can use the `ref` modifier in the declaration of a [structure type](struct.md). Instances of a `ref struct` type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref struct` types as follows: +Use the `ref` modifier when declaring a [structure type](struct.md). You allocate instances of a `ref struct` type on the stack, and they can't escape to the managed heap. To ensure this property, the compiler limits the usage of `ref struct` types as follows: -- A `ref struct` can't be the element type of an array. -- A `ref struct` can't be a declared type of a field of a class or a non-`ref struct`. -- A `ref struct` can't be boxed to or . -- A `ref struct` variable can't be captured in a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md). -- Before C# 13, `ref struct` variables can't be used in an `async` method. Beginning with C# 13, a `ref struct` variable can't be used in the same block as the [`await`](../operators/await.md) expression in an [`async`](../keywords/async.md) method. However, you can use `ref struct` variables in synchronous methods, for example, in methods that return or . -- Before C# 13, a `ref struct` variable can't be used in [iterators](../../iterators.md). Beginning with C# 13, `ref struct` types and `ref` locals can be used in iterators, provided they aren't in code segments with the `yield return` statement. +- You can't use a `ref struct` as the element type of an array. +- You can't declare a `ref struct` as the type of a field in a class or a non-`ref struct`. +- You can't box a `ref struct` to or . +- You can't capture a `ref struct` variable in a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md). +- Before C# 13, you can't use `ref struct` variables in an `async` method. Beginning with C# 13, a `ref struct` variable can't be used in the same block as the [`await`](../operators/await.md) expression in an [`async`](../keywords/async.md) method. However, you can use `ref struct` variables in synchronous methods, for example, in methods that return or . +- Before C# 13, you can't use a `ref struct` variable in [iterators](../../iterators.md). Beginning with C# 13, `ref struct` types and `ref` locals can be used in iterators, provided they aren't in code segments with the `yield return` statement. - Before C# 13, a `ref struct` can't implement interfaces. Beginning with C# 13, a `ref` struct can implement interfaces, but must adhere to the [ref safety](~/_csharpstandard/standard/structs.md#1623-ref-modifier) rules. For example, a `ref struct` type can't be converted to the interface type because that requires a boxing conversion. - Before C# 13, a `ref struct` can't be a type argument. Beginning with C# 13, a `ref struct` can be the type argument when the type parameter specifies the `allows ref struct` in its `where` clause. +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + Typically, you define a `ref struct` type when you need a type that also includes data members of `ref struct` types: :::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetRefStruct"::: @@ -36,9 +38,9 @@ A `ref` field can have the `null` value. Use the } ``` -The `Span` type stores a reference through which it accesses the contiguous elements in memory. The use of a reference enables a `Span` instance to avoid copying the storage it refers to. +The `Span` type stores a reference through which it accesses the contiguous elements in memory. By using a reference, a `Span` instance avoids copying the storage it refers to. ## The disposable pattern @@ -64,19 +66,19 @@ Beginning with C# 13, you can also implement the [!IMPORTANT] -> A `ref struct` that implements an interface includes the potential for later source-breaking and binary-breaking changes. The break occurs if a `ref struct` implements an interface defined in another assembly, and that assembly provides an update that adds default members to that interface. +> Implementing an interface with a `ref struct` type introduces the potential for later source-breaking and binary-breaking changes. The break occurs if a `ref struct` implements an interface defined in another assembly, and that assembly provides an update that adds default members to that interface. > -> The source-break happens when you recompile the `ref struct`: It must implement the new member, even though there's a default implementation. +> The source break happens when you recompile the `ref struct`: It must implement the new member, even though there's a default implementation. > -> The binary-break happens if you upgrade the external assembly without recompiling the `ref struct` type *and* the updated code calls the default implementation of the new method. The runtime throws an exception when the default member is accessed. +> The binary break happens if you upgrade the external assembly without recompiling the `ref struct` type *and* the updated code calls the default implementation of the new method. The runtime throws an exception when the default member is accessed. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/reference-types.md b/docs/csharp/language-reference/builtin-types/reference-types.md index 27457e22ad3cb..b38777bafa662 100644 --- a/docs/csharp/language-reference/builtin-types/reference-types.md +++ b/docs/csharp/language-reference/builtin-types/reference-types.md @@ -1,7 +1,7 @@ --- title: "Built-in reference types" description: "Learn about reference types that have C# keywords you can use to declare them." -ms.date: 11/18/2025 +ms.date: 01/14/2026 f1_keywords: - "object_CSharpKeyword" - "object" @@ -24,17 +24,19 @@ helpviewer_keywords: --- # Built-in reference types (C# reference) -C# has many built-in reference types. They have keywords or operators that are synonyms for a type in the .NET library. +C# has many built-in reference types. These types include keywords or operators that are synonyms for a type in the .NET library. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] ## The object type -The `object` type is an alias for in .NET. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from . You can assign values of any type (except `ref struct`, see [ref struct](ref-struct.md)) to variables of type `object`. Any `object` variable can be assigned to its default value using the literal `null`. When a variable of a value type is converted to object, it's *boxed*. When a variable of type `object` is converted to a value type, it's *unboxed*. For more information, see [Boxing and Unboxing](../../programming-guide/types/boxing-and-unboxing.md). +The `object` type is an alias for in .NET. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from . Assign values of any type (except `ref struct`, see [ref struct](ref-struct.md)) to variables of type `object`. You can assign the literal `null` to any `object` variable as its default value. When you convert a value type variable to `object`, the value is *boxed*. When you convert a variable of type `object` to a value type, the value is *unboxed*. For more information, see [Boxing and Unboxing](../../programming-guide/types/boxing-and-unboxing.md). ## The string type -The `string` type represents a sequence of zero or more Unicode characters. `string` is an alias for in .NET. +The `string` type represents a sequence of zero or more Unicode characters. In .NET, `string` is an alias for . -Although `string` is a reference type, the [equality operators `==` and `!=`](../operators/equality-operators.md#string-equality) are defined to compare the values of `string` objects, not references. Value based equality makes testing for string equality more intuitive. For example: +Although `string` is a reference type, the [equality operators `==` and `!=`](../operators/equality-operators.md#string-equality) compare the values of `string` objects, not references. Value-based equality makes testing for string equality more intuitive. For example: ```csharp string a = "hello"; @@ -45,7 +47,7 @@ Console.WriteLine(a == b); Console.WriteLine(object.ReferenceEquals(a, b)); ``` -The previous example displays "True" and then "False" because the content of the strings is equivalent, but `a` and `b` don't refer to the same string instance. +The preceding example displays "True" and then "False" because the content of the strings is equivalent, but `a` and `b` don't refer to the same string instance. The [+ operator](../operators/addition-operator.md#string-concatenation) concatenates strings: @@ -55,21 +57,21 @@ string a = "good " + "morning"; The preceding code creates a string object that contains "good morning". -Strings are *immutable*--the contents of a string object can't be changed after the object is created. For example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and that new object is assigned to `b`. The memory allocated for `b` (when it contained the string "h") is then eligible for garbage collection. +Strings are *immutable* - you can't change the contents of a string object after you create it. For example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and assigns that new object to `b`. The memory allocated for `b` (when it contained the string "h") is then eligible for garbage collection. ```csharp string b = "h"; b += "ello"; ``` -The `[]` [operator](../operators/member-access-operators.md#indexer-operator-) can be used for readonly access to individual characters of a string. Valid index values start at `0` and must be less than the length of the string: +You can use the `[]` [operator](../operators/member-access-operators.md#indexer-operator-) for readonly access to individual characters of a string. Valid index values start at `0` and must be less than the length of the string: ```csharp string str = "test"; char x = str[2]; // x = 's'; ``` -In similar fashion, the `[]` operator can also be used for iterating over each character in a string: +In similar fashion, you can use the `[]` operator for iterating over each character in a string: ```csharp string str = "test"; @@ -83,7 +85,7 @@ for (int i = 0; i < str.Length; i++) ### String literals -String literals are of type `string` and can be written in three forms, raw, quoted, and verbatim. +String literals are of type `string` and come in three forms: raw, quoted, and verbatim. *Raw string literals* contain arbitrary text without requiring escape sequences. Raw string literals can include whitespace and new lines, embedded quotes, and other special characters. Raw string literals are enclosed in a minimum of three double quotation marks ("""): @@ -139,7 +141,7 @@ var json= """ [!INCLUDE[raw-string-tip](../../includes/raw-string-parsing.md)] -The compiler issues an error if any of the text lines extend to the left of the closing quote sequence. The opening and closing quote sequences can be on the same line, providing the string literal neither starts nor ends with a quote character: +The compiler returns an error if any of the text lines extend to the left of the closing quote sequence. The opening and closing quote sequences can be on the same line, providing the string literal neither starts nor ends with a quote character: ```csharp var shortText = """He said "hello!" this morning."""; @@ -172,7 +174,7 @@ Console.WriteLine(a); @"good morning" // a string literal ``` -The advantage of verbatim strings is that escape sequences *aren't* processed, which makes it easy to write. For example, the following text matches a fully qualified Windows file name: +The advantage of verbatim strings is that escape sequences *aren't* processed, which makes them easy to write. For example, the following text matches a fully qualified Windows file name: ```csharp @"c:\Docs\Source\a.txt" // rather than "c:\\Docs\\Source\\a.txt" @@ -186,20 +188,20 @@ To include a double quotation mark in an @-quoted string, double it: ### UTF-8 string literals -Strings in .NET are stored using UTF-16 encoding. UTF-8 is the standard for Web protocols and other important libraries. You can add the `u8` suffix to a string literal to specify UTF-8 encoding. UTF-8 literals are stored as `ReadOnlySpan` objects. The natural type of a UTF-8 string literal is `ReadOnlySpan`. Using a UTF-8 string literal creates a more clear declaration than declaring the equivalent , as shown in the following code: +.NET stores strings using UTF-16 encoding. UTF-8 is the standard for Web protocols and other important libraries. You can add the `u8` suffix to a string literal to specify UTF-8 encoding. The compiler stores UTF-8 literals as `ReadOnlySpan` objects. Using a UTF-8 string literal creates a more clear declaration than declaring the equivalent , as shown in the following code: ```csharp ReadOnlySpan AuthWithTrailingSpace = new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 }; ReadOnlySpan AuthStringLiteral = "AUTH "u8; ``` -To store a UTF-8 string literal as an array requires the use of to copy the bytes containing the literal to the mutable array: +To store a UTF-8 string literal as an array, use to copy the bytes containing the literal to the mutable array: ```csharp byte[] AuthStringLiteral = "AUTH "u8.ToArray(); ``` -UTF-8 string literals aren't compile time constants; they're runtime constants. Therefore, they can't be used as the default value for an optional parameter. UTF-8 string literals can't be combined with string interpolation. You can't use the `$` token and the `u8` suffix on the same string expression. +UTF-8 string literals aren't compile-time constants; they're runtime constants. Therefore, they can't be used as the default value for an optional parameter. You can't combine UTF-8 string literals with string interpolation. You can't use the `$` token and the `u8` suffix on the same string expression. ## The delegate type @@ -212,9 +214,9 @@ public delegate int AnotherDelegate(MyType m, long num); In .NET, `System.Action` and `System.Func` types provide generic definitions for many common delegates. You likely don't need to define new custom delegate types. Instead, you can create instantiations of the provided generic types. -A `delegate` is a built-in reference type that can be used to encapsulate a named or an anonymous method. Delegates are similar to function pointers in C++; however, delegates are type-safe and secure. For applications of delegates, see [Delegates](../../programming-guide/delegates/index.md) and [Generic Delegates](../../programming-guide/generics/generic-delegates.md). Delegates are the basis for [Events](../../programming-guide/events/index.md). A delegate can be instantiated by associating it either with a named or anonymous method. +A `delegate` is a built-in reference type that you can use to encapsulate a named or an anonymous method. Delegates are similar to function pointers in C++; however, delegates are type-safe and secure. For applications of delegates, see [Delegates](../../programming-guide/delegates/index.md) and [Generic Delegates](../../programming-guide/generics/generic-delegates.md). Delegates are the basis for [Events](../../programming-guide/events/index.md). You instantiate a delegate by associating it with either a named or anonymous method. -The delegate must be instantiated with a method or lambda expression that has a compatible return type and input parameters. For more information on the degree of variance that is allowed in the method signature, see [Variance in Delegates](../../programming-guide/concepts/covariance-contravariance/using-variance-in-delegates.md). For use with anonymous methods, the delegate and the code to be associated with it are declared together. +You must instantiate the delegate with a method or lambda expression that has a compatible return type and input parameters. For more information on the degree of variance that is allowed in the method signature, see [Variance in Delegates](../../programming-guide/concepts/covariance-contravariance/using-variance-in-delegates.md). For use with anonymous methods, declare the delegate and the code to be associated with it together. Delegate combination or removal fails with a runtime exception when the delegate types involved at run time are different due to variant conversion. The following example demonstrates a situation that fails: @@ -245,11 +247,11 @@ You can declare [*function pointers*](../unsafe-code.md#function-pointers), whic ## The dynamic type -The `dynamic` type indicates that use of the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time. The `dynamic` type simplifies access to COM APIs such as the Office Automation APIs, to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM). +The `dynamic` type indicates that the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time. The `dynamic` type simplifies access to COM APIs such as the Office Automation APIs, to dynamic APIs such as IronPython libraries, and to the HTML Document Object Model (DOM). -Type `dynamic` behaves like type `object` in most circumstances. In particular, any non-null expression can be converted to the `dynamic` type. The `dynamic` type differs from `object` in that operations that contain expressions of type `dynamic` aren't resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type `dynamic` are compiled into variables of type `object`. Therefore, type `dynamic` exists only at compile time, not at run time. +Type `dynamic` behaves like type `object` in most circumstances. In particular, any non-null expression can be converted to the `dynamic` type. The `dynamic` type differs from `object` in that the compiler doesn't resolve or type check operations that contain expressions of type `dynamic`. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type `dynamic` are compiled into variables of type `object`. Therefore, type `dynamic` exists only at compile time, not at run time. -The following example contrasts a variable of type `dynamic` to a variable of type `object`. To verify the type of each variable at compile time, place the mouse pointer over `dyn` or `obj` in the `WriteLine` statements. Copy the following code into an editor where IntelliSense is available. IntelliSense shows **dynamic** for `dyn` and **object** for `obj`. +The following example contrasts a variable of type `dynamic` with a variable of type `object`. To verify the type of each variable at compile time, place the mouse pointer over `dyn` or `obj` in the `WriteLine` statements. Copy the following code into an editor where IntelliSense is available. IntelliSense shows **dynamic** for `dyn` and **object** for `obj`. [!code-csharp[csrefKeywordsTypes#21](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/dynamic1.cs#21)] diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index 7fadfdfd79a3f..eb9cba3948449 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -1,7 +1,7 @@ --- title: "Structure types" description: Learn about the struct type in C# -ms.date: 11/18/2025 +ms.date: 01/14/2026 f1_keywords: - "struct_CSharpKeyword" helpviewer_keywords: @@ -11,26 +11,30 @@ helpviewer_keywords: --- # Structure types (C# reference) -A *structure type* (or *struct type*) is a [value type](value-types.md) that can encapsulate data and related functionality. You use the `struct` keyword to define a structure type: +A *structure type* (or *struct type*) is a [value type](value-types.md) that can encapsulate data and related functionality. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +Use the `struct` keyword to define a structure type: :::code language="csharp" source="snippets/shared/StructType.cs" id="StructExample"::: For information about `ref struct` and `readonly ref struct` types, see the [ref structure types](ref-struct.md) article. -Structure types have *value semantics*. That is, a variable of a structure type contains an instance of the type. By default, variable values are copied on assignment, passing an argument to a method, and returning a method result. For structure-type variables, an instance of the type is copied. For more information, see [Value types](value-types.md). +Structure types have *value semantics*. That is, a variable of a structure type contains an instance of the type. By default, the system copies variable values on assignment, when passing an argument to a method, and when returning a method result. For structure-type variables, the system copies an instance of the type. For more information, see [Value types](value-types.md). -Typically, you use structure types to design small data-centric types that provide little or no behavior. For example, .NET uses structure types to represent a number (both [integer](integral-numeric-types.md) and [real](floating-point-numeric-types.md)), a [Boolean value](bool.md), a [Unicode character](char.md), a [time instance](xref:System.DateTime). If you're focused on the behavior of a type, consider defining a [class](../keywords/class.md). Class types have *reference semantics*. That is, a variable of a class type contains a reference to an instance of the type, not the instance itself. +Typically, you use structure types to design small data-centric types that provide little or no behavior. For example, .NET uses structure types to represent a number (both [integer](integral-numeric-types.md) and [real](floating-point-numeric-types.md)), a [Boolean value](bool.md), a [Unicode character](char.md), and a [time instance](xref:System.DateTime). If you're focused on the behavior of a type, consider defining a [class](../keywords/class.md). Class types have *reference semantics*. That is, a variable of a class type contains a reference to an instance of the type, not the instance itself. Because structure types have value semantics, we recommend you define *immutable* structure types. ## `readonly` struct -You use the `readonly` modifier to declare that a structure type is immutable. All data members of a `readonly` struct must be read-only as follows: +Use the `readonly` modifier to declare that a structure type is immutable. All data members of a `readonly` struct must be read-only as follows: - Any field declaration must have the [`readonly` modifier](../keywords/readonly.md). - Any property, including automatically implemented ones, must be read-only or [`init` only](../keywords/init.md). Init-only setters are only available from [C# version 9 onwards](../../whats-new/csharp-version-history.md). -That guarantees that no member of a `readonly` struct modifies the state of the struct. That means that other instance members except constructors are implicitly [`readonly`](#readonly-instance-members). +This rule guarantees that no member of a `readonly` struct modifies the state of the struct. All other instance members except constructors are implicitly [`readonly`](#readonly-instance-members). > [!NOTE] > In a `readonly` struct, a data member of a mutable reference type still can mutate its own state. For example, you can't replace a instance, but you can add new elements to it. @@ -41,13 +45,13 @@ The following code defines a `readonly` struct with init-only property setters: ## `readonly` instance members -You can also use the `readonly` modifier to declare that an instance member doesn't modify the state of a struct. If you can't declare the whole structure type as `readonly`, use the `readonly` modifier to mark the instance members that don't modify the state of the struct. +Use the `readonly` modifier to declare that an instance member doesn't modify the state of a struct. If you can't declare the whole structure type as `readonly`, use the `readonly` modifier to mark the instance members that don't modify the state of the struct. -Within a `readonly` instance member, you can't assign to structure's instance fields. However, a `readonly` member can call a non-`readonly` member. In that case, the compiler creates a copy of the structure instance and calls the non-`readonly` member on that copy. As a result, the original structure instance isn't modified. +Within a `readonly` instance member, you can't assign to the structure's instance fields. However, a `readonly` member can call a non-`readonly` member. In that case, the compiler creates a copy of the structure instance and calls the non-`readonly` member on that copy. As a result, the original structure instance isn't modified. Typically, you apply the `readonly` modifier to the following kinds of instance members: -- methods: +- Methods: :::code language="csharp" source="snippets/shared/StructType.cs" id="ReadonlyMethod"::: @@ -55,26 +59,26 @@ Typically, you apply the `readonly` modifier to the following kinds of instance :::code language="csharp" source="snippets/shared/StructType.cs" id="ReadonlyOverride"::: -- properties and indexers: +- Properties and indexers: :::code language="csharp" source="snippets/shared/StructType.cs" id="ReadonlyProperty"::: If you need to apply the `readonly` modifier to both accessors of a property or indexer, apply it in the declaration of the property or indexer. > [!NOTE] - > The compiler declares a `get` accessor of an [automatically implemented property](../../programming-guide/classes-and-structs/auto-implemented-properties.md) as `readonly`, regardless of presence of the `readonly` modifier in a property declaration. + > The compiler declares a `get` accessor of an [automatically implemented property](../../programming-guide/classes-and-structs/auto-implemented-properties.md) as `readonly`, regardless of the presence of the `readonly` modifier in a property declaration. You can apply the `readonly` modifier to a property or indexer with an `init` accessor: :::code language="csharp" source="snippets/shared/StructType.cs" id="ReadonlyWithInit"::: -You can apply the `readonly` modifier to static fields of a structure type, but not any other static members, such as properties or methods. +You can apply the `readonly` modifier to static fields of a structure type, but not to any other static members, such as properties or methods. The compiler can make use of the `readonly` modifier for performance optimizations. For more information, see [Avoiding allocations](../../advanced-topics/performance/index.md). ## Nondestructive mutation -You can use the [`with` expression](../operators/with-expression.md) to produce a copy of a structure-type instance with the specified properties and fields modified. You use [object initializer](../../programming-guide/classes-and-structs/object-and-collection-initializers.md) syntax to specify what members to modify and their new values, as the following example shows: +Use the [`with` expression](../operators/with-expression.md) to create a copy of a structure-type instance with the specified properties and fields changed. Use [object initializer](../../programming-guide/classes-and-structs/object-and-collection-initializers.md) syntax to specify which members to modify and their new values, as the following example shows: :::code language="csharp" source="snippets/shared/StructType.cs" id="WithExpression"::: @@ -84,7 +88,7 @@ You can define record structure types. Record types provide built-in functionali ## Inline arrays -Beginning with C# 12, you can declare *inline arrays* as a `struct` type: +Starting with C# 12, you can declare *inline arrays* as a `struct` type: :::code language="csharp" source="snippets/shared/StructType.cs" id="DeclareInlineArray"::: @@ -98,7 +102,7 @@ In addition, the compiler validates the 0`). - The target type must be a struct. -In most cases, an inline array can be accessed like an array, both to read and write values. In addition, you can use the [range](../operators/member-access-operators.md#range-operator-) and [index](../operators/member-access-operators.md#indexer-access) operators. +In most cases, you can access an inline array like an array, both to read and write values. You can also use the [range](../operators/member-access-operators.md#range-operator-) and [index](../operators/member-access-operators.md#indexer-access) operators. There are minimal restrictions on the type of the single field of an inline array. It can't be a pointer type: @@ -114,7 +118,7 @@ Inline arrays are an advanced language feature. They're intended for high-perfor ## Struct initialization and default values -A variable of a `struct` type directly contains the data for that `struct`. That creates a distinction between an uninitialized `struct`, which has its default value and an initialized `struct`, which stores values set by constructing it. For example, consider the following code: +A variable of a `struct` type directly contains the data for that `struct`. This direct data storage creates a distinction between an uninitialized `struct`, which has its default value, and an initialized `struct`, which stores values set by constructing it. For example, consider the following code: :::code language="csharp" source="snippets/shared/StructType.cs" id="ParameterlessConstructor"::: @@ -127,10 +131,10 @@ The most common situation where you see default values is in arrays or in other TemperatureRange[] lastMonth = new TemperatureRange[30]; ``` -All of a struct's member fields must be *definitely assigned* when created because `struct` types directly store their data. The `default` value of a struct *definitely assigned* all fields to 0. All fields must be definitely assigned when a constructor is invoked. You initialize fields using the following mechanisms: +All of a struct's member fields must be *definitely assigned* when created because `struct` types directly store their data. The `default` value of a struct *definitely assigns* all fields to 0. All fields must be definitely assigned when a constructor is invoked. You initialize fields by using the following mechanisms: -- You can add *field initializers* to any field or auto implemented property. -- You can initialize any fields, or auto properties, in the body of the constructor. +- Add *field initializers* to any field or auto-implemented property. +- Initialize any fields or auto properties in the body of the constructor. If you don't initialize all fields in a struct, the compiler adds code to the constructor that initializes those fields to the default value. A struct assigned to its `default` value is initialized to the 0-bit pattern. A struct initialized with `new` is initialized to the 0-bit pattern, followed by executing any field initializers and a constructor. @@ -140,7 +144,7 @@ Every `struct` has a `public` parameterless constructor. If you write a paramete Beginning with C# 12, `struct` types can define a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) as part of its declaration. Primary constructors provide a concise syntax for constructor parameters that can be used throughout the `struct` body, in any member declaration for that struct. -If all instance fields of a structure type are accessible, you can also instantiate it without the `new` operator. In that case you must initialize all instance fields before the first use of the instance. The following example shows how to do that: +If all instance fields of a structure type are accessible, you can also instantiate it without the `new` operator. In that case, you must initialize all instance fields before the first use of the instance. The following example shows how to do that: :::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetWithoutNew"::: @@ -160,11 +164,11 @@ When you pass a structure-type variable to a method as an argument or return a s ## `struct` constraint -You also use the `struct` keyword in the [`struct` constraint](../../programming-guide/generics/constraints-on-type-parameters.md) to specify that a type parameter is a non-nullable value type. Both structure and [enumeration](enum.md) types satisfy the `struct` constraint. +Use the `struct` keyword in the [`struct` constraint](../../programming-guide/generics/constraints-on-type-parameters.md) to specify that a type parameter is a non-nullable value type. Both structure and [enumeration](enum.md) types satisfy the `struct` constraint. ## Conversions -For any structure type (except [`ref struct`](ref-struct.md) types), there exist [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the and types. There exist also boxing and unboxing conversions between a structure type and any interface that it implements. +For any structure type (except [`ref struct`](ref-struct.md) types), [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions exist to and from the and types. Boxing and unboxing conversions also exist between a structure type and any interface that it implements. ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/unmanaged-types.md b/docs/csharp/language-reference/builtin-types/unmanaged-types.md index b7a9852b409fc..b1b9cbc2f5e47 100644 --- a/docs/csharp/language-reference/builtin-types/unmanaged-types.md +++ b/docs/csharp/language-reference/builtin-types/unmanaged-types.md @@ -1,7 +1,7 @@ --- description: Learn about unmanaged types in C# title: "Unmanaged types" -ms.date: 09/06/2019 +ms.date: 01/14/2026 helpviewer_keywords: - "unmanaged type [C#]" --- @@ -17,13 +17,15 @@ A type is an **unmanaged type** if it's any of the following types: You can use the [`unmanaged` constraint](../../programming-guide/generics/constraints-on-type-parameters.md#unmanaged-constraint) to specify that a type parameter is a non-pointer, non-nullable unmanaged type. +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + A *constructed* struct type that contains fields of unmanaged types only is also unmanaged, as the following example shows: -[!code-csharp[unmanaged constructed types](snippets/shared/UnmanagedTypes.cs#ProgramExample)] +:::code language="csharp" source="snippets/shared/UnmanagedTypes.cs" id="ProgramExample"::: -A generic struct may be the source of both unmanaged and managed constructed types. The preceding example defines a generic struct `Coords` and presents the examples of unmanaged constructed types. The example of a managed type is `Coords`. It's managed because it has the fields of the `object` type, which is managed. If you want *all* constructed types to be unmanaged types, use the `unmanaged` constraint in the definition of a generic struct: +A generic struct can define both unmanaged and managed constructed types. The preceding example defines a generic struct `Coords` and presents examples of unmanaged constructed types. The example of a managed type is `Coords`. It's managed because it has the fields of the `object` type, which is managed. If you want *all* constructed types to be unmanaged types, use the `unmanaged` constraint in the definition of a generic struct: -[!code-csharp[unmanaged constraint in type definition](snippets/shared/UnmanagedTypes.cs#AlwaysUnmanaged)] +:::code language="csharp" source="snippets/shared/UnmanagedTypes.cs" id="AlwaysUnmanaged"::: ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/value-tuples.md b/docs/csharp/language-reference/builtin-types/value-tuples.md index bd2f97fe73080..878ce1f40298a 100644 --- a/docs/csharp/language-reference/builtin-types/value-tuples.md +++ b/docs/csharp/language-reference/builtin-types/value-tuples.md @@ -1,31 +1,35 @@ --- title: "Tuple types" description: "C# tuples: lightweight data structures that you can use to group loosely related data elements. Tuples introduce a type that contains multiple public members." -ms.date: 04/24/2023 +ms.date: 01/14/2026 helpviewer_keywords: - "value tuples [C#]" --- # Tuple types (C# reference) -The *tuples* feature provides concise syntax to group multiple data elements in a lightweight data structure. The following example shows how you can declare a tuple variable, initialize it, and access its data members: +The *tuples* feature provides a concise syntax to group multiple data elements in a lightweight data structure. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +The following example shows how you can declare a tuple variable, initialize it, and access its data members: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="Introduction"::: -As the preceding example shows, to define a tuple type, you specify types of all its data members and, optionally, the [field names](#tuple-field-names). You can't define methods in a tuple type, but you can use the methods provided by .NET, as the following example shows: +As the preceding example shows, to define a tuple type, you specify the types of all its data members and, optionally, the [field names](#tuple-field-names). You can't define methods in a tuple type, but you can use the methods provided by .NET, as the following example shows: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="MethodOnTuples"::: Tuple types support [equality operators](../operators/equality-operators.md) `==` and `!=`. For more information, see the [Tuple equality](#tuple-equality) section. -Tuple types are [value types](value-types.md); tuple elements are public fields. That makes tuples *mutable* value types. +Tuple types are [value types](value-types.md); tuple elements are public fields. That design makes tuples *mutable* value types. -You can define tuples with an arbitrary large number of elements: +You can define tuples with an arbitrarily large number of elements: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="LargeTuple"::: -## Use cases of tuples +## Use cases for tuples -One of the most common use cases of tuples is as a method return type. That is, instead of defining [`out` method parameters](../keywords/method-parameters.md#out-parameter-modifier), you can group method results in a tuple return type, as the following example shows: +One of the most common use cases for tuples is as a method return type. Instead of defining [`out` method parameters](../keywords/method-parameters.md#out-parameter-modifier), group method results in a tuple return type, as the following example shows: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="MultipleReturns"::: @@ -33,26 +37,26 @@ As the preceding example shows, you can work with the returned tuple instance di You can also use tuple types instead of [anonymous types](../../fundamentals/types/anonymous-types.md); for example, in LINQ queries. For more information, see [Choosing between anonymous and tuple types](../../../standard/base-types/choosing-between-anonymous-and-tuple.md). -Typically, you use tuples to group loosely related data elements. In public APIs, consider defining a [class](../keywords/class.md) or a [structure](struct.md) type. +Typically, use tuples to group loosely related data elements. In public APIs, consider defining a [class](../keywords/class.md) or a [structure](struct.md) type. ## Tuple field names -You explicitly specify tuple fields names in a tuple initialization expression or in the definition of a tuple type, as the following example shows: +You explicitly specify tuple field names in a tuple initialization expression or in the definition of a tuple type, as the following example shows: [!code-csharp[explicit field names](snippets/shared/ValueTuples.cs#ExplicitFieldNames)] -If you don't specify a field name, it may be inferred from the name of the corresponding variable in a tuple initialization expression, as the following example shows: +If you don't specify a field name, the compiler might infer it from the name of the corresponding variable in a tuple initialization expression, as the following example shows: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="InferFieldNames"::: -That's called tuple projection initializers. The name of a variable isn't projected onto a tuple field name in the following cases: +This feature is called tuple projection initializers. The name of a variable isn't projected onto a tuple field name in the following cases: - The candidate name is a member name of a tuple type, for example, `Item3`, `ToString`, or `Rest`. - The candidate name is a duplicate of another tuple field name, either explicit or implicit. In the preceding cases, you either explicitly specify the name of a field or access a field by its default name. -The default names of tuple fields are `Item1`, `Item2`, `Item3` and so on. You can always use the default name of a field, even when a field name is specified explicitly or inferred, as the following example shows: +The default names of tuple fields are `Item1`, `Item2`, `Item3`, and so on. You can always use the default name of a field, even when a field name is specified explicitly or inferred, as the following example shows: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="DefaultFieldNames"::: @@ -91,14 +95,14 @@ An alias for a tuple type provides more semantic information when you use tuples C# supports assignment between tuple types that satisfy both of the following conditions: -- both tuple types have the same number of elements -- for each tuple position, the type of the right-hand tuple element is the same as or implicitly convertible to the type of the corresponding left-hand tuple element +- Both tuple types have the same number of elements. +- For each tuple position, the type of the right-hand tuple element is the same as or implicitly convertible to the type of the corresponding left-hand tuple element. -Tuple element values are assigned following the order of tuple elements. The names of tuple fields are ignored and not assigned, as the following example shows: +Assign tuple element values by following the order of tuple elements. The assignment process ignores the names of tuple fields, as the following example shows: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="Assignment"::: -You can also use the assignment operator `=` to *deconstruct* a tuple instance in separate variables. You can do that in many ways: +Use the assignment operator `=` to *deconstruct* a tuple instance into separate variables. You can do that in many ways: - Use the `var` keyword outside the parentheses to declare implicitly typed variables and let the compiler infer their types: @@ -130,26 +134,26 @@ Tuple types support the `==` and `!=` operators. These operators compare members :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="TupleEquality"::: -As the preceding example shows, the `==` and `!=` operations don't take into account tuple field names. +As the preceding example shows, the `==` and `!=` operations don't take tuple field names into account. Two tuples are comparable when both of the following conditions are satisfied: - Both tuples have the same number of elements. For example, `t1 != t2` doesn't compile if `t1` and `t2` have different numbers of elements. -- For each tuple position, the corresponding elements from the left-hand and right-hand tuple operands are comparable with the `==` and `!=` operators. For example, `(1, (2, 3)) == ((1, 2), 3)` doesn't compile because `1` isn't comparable with `(1, 2)`. +- For each tuple position, the corresponding elements from the left-hand and right-hand tuple operands are comparable by using the `==` and `!=` operators. For example, `(1, (2, 3)) == ((1, 2), 3)` doesn't compile because `1` isn't comparable with `(1, 2)`. -The `==` and `!=` operators compare tuples in short-circuiting way. That is, an operation stops as soon as it meets a pair of non equal elements or reaches the ends of tuples. However, before any comparison, *all* tuple elements are evaluated, as the following example shows: +The `==` and `!=` operators compare tuples in a short-circuiting way. That is, an operation stops as soon as it meets a pair of non equal elements or reaches the ends of tuples. However, before any comparison, *all* tuple elements are evaluated, as the following example shows: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="TupleEvaluationForEquality"::: ## Tuples as out parameters -Typically, you refactor a method that has [`out` parameters](../keywords/method-parameters.md#out-parameter-modifier) into a method that returns a tuple. However, there are cases in which an `out` parameter can be of a tuple type. The following example shows how to work with tuples as `out` parameters: +Typically, you refactor a method that has [`out` parameters](../keywords/method-parameters.md#out-parameter-modifier) into a method that returns a tuple. However, some cases exist where an `out` parameter can be a tuple type. The following example shows how to work with tuples as `out` parameters: :::code language="csharp" source="snippets/shared/ValueTuples.cs" id="TupleAsOutParameter"::: ## Tuples vs `System.Tuple` -C# tuples, which are backed by types, are different from tuples that are represented by types. The main differences are as follows: +C# tuples use types and differ from tuples that use types. The main differences are: - `System.ValueTuple` types are [value types](value-types.md). `System.Tuple` types are [reference types](../keywords/reference-types.md). - `System.ValueTuple` types are mutable. `System.Tuple` types are immutable. diff --git a/docs/csharp/language-reference/builtin-types/value-types.md b/docs/csharp/language-reference/builtin-types/value-types.md index 9d8a98face453..e6d03c3df25ab 100644 --- a/docs/csharp/language-reference/builtin-types/value-types.md +++ b/docs/csharp/language-reference/builtin-types/value-types.md @@ -1,26 +1,25 @@ --- description: Value types vs reference types, kinds of value types, and the built-in value types in C# title: "Value types" -ms.date: 01/22/2020 +ms.date: 01/14/2026 f1_keywords: - "cs.valuetypes" helpviewer_keywords: - "value types [C#]" - "types [C#], value types" - "C# language, value types" -ms.assetid: 471eb994-2958-49d5-a6be-19b4313f80a3 --- # Value types (C# reference) -*Value types* and [reference types](../keywords/reference-types.md) are the two main categories of C# types. A variable of a value type contains an instance of the type. This differs from a variable of a reference type, which contains a reference to an instance of the type. By default, on [assignment](../operators/assignment-operator.md), passing an argument to a method, and returning a method result, variable values are copied. In the case of value-type variables, the corresponding type instances are copied. The following example demonstrates that behavior: +*Value types* and [reference types](../keywords/reference-types.md) are the two main categories of C# types. A variable of a value type contains an instance of the type. This behavior differs from a variable of a reference type, which contains a reference to an instance of the type. By default, on [assignment](../operators/assignment-operator.md), passing an argument to a method, and returning a method result, variable values are copied. In the case of value-type variables, the corresponding type instances are copied. The following example demonstrates that behavior: -[!code-csharp[copy of values](snippets/shared/ValueTypes.cs#ValueTypeCopied)] +:::code language="csharp" source="snippets/shared/ValueTypes.cs" id="ValueTypeCopied"::: As the preceding example shows, operations on a value-type variable affect only that instance of the value type, stored in the variable. If a value type contains a data member of a reference type, only the reference to the instance of the reference type is copied when a value-type instance is copied. Both the copy and original value-type instance have access to the same reference-type instance. The following example demonstrates that behavior: -[!code-csharp[shallow copy](snippets/shared/ValueTypes.cs#ShallowCopy)] +:::code language="csharp" source="snippets/shared/ValueTypes.cs" id="ShallowCopy"::: > [!NOTE] > To make your code less error-prone and more robust, define and use immutable value types. This article uses mutable value types only for demonstration purposes. @@ -32,7 +31,7 @@ A value type can be one of the two following kinds: - a [structure type](struct.md), which encapsulates data and related functionality - an [enumeration type](enum.md), which is defined by a set of named constants and represents a choice or a combination of choices -A [nullable value type](nullable-value-types.md) `T?` represents all values of its underlying value type `T` and an additional [null](../keywords/null.md) value. You cannot assign `null` to a variable of a value type, unless it's a nullable value type. +A [nullable value type](nullable-value-types.md) `T?` represents all values of its underlying value type `T` and an additional [null](../keywords/null.md) value. You can't assign `null` to a variable of a value type, unless it's a nullable value type. You can use the [`struct` constraint](../../programming-guide/generics/constraints-on-type-parameters.md) to specify that a type parameter is a non-nullable value type. Both structure and enumeration types satisfy the `struct` constraint. You can use `System.Enum` in a base class constraint (that is known as the [enum constraint](../../programming-guide/generics/constraints-on-type-parameters.md#enum-constraints)) to specify that a type parameter is an enumeration type. @@ -45,14 +44,14 @@ C# provides the following built-in value types, also known as *simple types*: - [bool](bool.md) that represents a Boolean value - [char](char.md) that represents a Unicode UTF-16 character -All simple types are structure types and differ from other structure types in that they permit certain additional operations: +All simple types are structure types. They differ from other structure types in that they permit certain additional operations: - You can use literals to provide a value of a simple type. -
For example, `'A'` is a literal of the type `char`, `2001` is a literal of the type `int` and `12.34m` is a literal of the type `decimal`. +
For example, `'A'` is a literal of the type `char`, `2001` is a literal of the type `int`, and `12.34m` is a literal of the type `decimal`. -- You can declare constants of the simple types with the [const](../keywords/const.md) keyword. +- You can declare constants of the simple types by using the [const](../keywords/const.md) keyword.
For example, you can define `const decimal = 12.34m`. -
It's not possible to have constants of other structure types. +
You can't declare constants of other structure types. - Constant expressions, whose operands are all constants of the simple types, are evaluated at compile time. diff --git a/docs/csharp/language-reference/builtin-types/void.md b/docs/csharp/language-reference/builtin-types/void.md index 8b4169a49eca2..194bd79a64d2b 100644 --- a/docs/csharp/language-reference/builtin-types/void.md +++ b/docs/csharp/language-reference/builtin-types/void.md @@ -1,24 +1,25 @@ --- description: Learn more about void keyword in C# title: "void" -ms.date: 02/11/2020 +ms.date: 01/14/2026 f1_keywords: - "void_CSharpKeyword" - "void" - "(void)" helpviewer_keywords: - "void keyword [C#]" -ms.assetid: 0d2d8a95-fe20-4fbd-bf5d-c1e54bce71d4 --- # void (C# reference) -You use `void` as the return type of a [method](../../programming-guide/classes-and-structs/methods.md) (or a [local function](../../programming-guide/classes-and-structs/local-functions.md)) to specify that the method doesn't return a value. +Use `void` as the return type of a [method](../../programming-guide/classes-and-structs/methods.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md) to specify that the method doesn't return a value. -[!code-csharp[void method](snippets/shared/VoidType.cs#VoidExample)] +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +:::code language="csharp" source="snippets/shared/VoidType.cs" id="VoidExample"::: You can also use `void` as a referent type to declare a pointer to an unknown type. For more information, see [Pointer types](../unsafe-code.md#pointer-types). -You cannot use `void` as the type of a variable. +You can't use `void` as the type of a variable. ## See also diff --git a/docs/csharp/language-reference/compiler-messages/file-local-types.md b/docs/csharp/language-reference/compiler-messages/file-local-types.md new file mode 100644 index 0000000000000..c5622f0a5db02 --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/file-local-types.md @@ -0,0 +1,82 @@ +--- +title: Resolve errors and warnings in file-local types +description: Learn how to diagnose and correct C# compiler errors and warnings when you declare file local types, or write source generators that create file local types. +f1_keywords: + - "CS9051" + - "CS9052" + - "CS9053" + - "CS9054" + - "CS9055" + - "CS9056" + - "CS9068" + - "CS9069" + - "CS9071" +helpviewer_keywords: + - "CS9051" + - "CS9052" + - "CS9053" + - "CS9054" + - "CS9055" + - "CS9056" + - "CS9068" + - "CS9069" + - "CS9071" +ms.date: 01/13/2026 +ai-usage: ai-assisted +--- +# Resolve errors and warnings for file local types + +The C# compiler generates errors and warnings when you misuse [file-local types](../keywords/file.md). File-local types are visible only within the file where you declare them. These diagnostics help you follow the rules for declaring and using file-local types. + + +- [**CS9051**](#visibility-restrictions): *File-local type cannot be used in a member signature in non-file-local type.* +- [**CS9052**](#visibility-restrictions): *File-local type cannot use accessibility modifiers.* +- [**CS9053**](#visibility-restrictions): *File-local type cannot be used as a base type of non-file-local type.* +- [**CS9054**](#declaration-rules): *File-local type must be defined in a top level type; it is a nested type.* +- [**CS9055**](#visibility-restrictions): *File-local type cannot be used in a 'global using static' directive.* +- [**CS9056**](#declaration-rules): *Types and aliases cannot be named 'file'.* +- [**CS9068**](#file-path-requirements): *File-local type must be declared in a file with a unique path. Path is used in multiple files.* +- [**CS9069**](#file-path-requirements): *File-local type cannot be used because the containing file path cannot be converted into the equivalent UTF-8 byte representation.* +- [**CS9071**](#declaration-rules): *The namespace already contains a definition for the type in this file.* + +## Visibility restrictions + +- **CS9051**: *File-local type cannot be used in a member signature in non-file-local type.* +- **CS9052**: *File-local type cannot use accessibility modifiers.* +- **CS9053**: *File-local type cannot be used as a base type of non-file-local type.* +- **CS9055**: *File-local type cannot be used in a 'global using static' directive.* + +A [file-local type](../keywords/file.md) is visible only within the file containing its declaration. The compiler enforces restrictions to prevent file-local types from "leaking" outside their intended scope: + +- A file-local type can't appear in the signature (parameters, return type, or type constraints) of any member declared in a non-file-local type (**CS9051**). This restriction ensures that code in other files doesn't depend on types it can't access. +- File-local types can't have explicit accessibility modifiers like `public`, `internal`, or `private` (**CS9052**). The `file` modifier already defines the type's visibility scope, making other access modifiers meaningless. +- A non-file-local type can't inherit from a file-local type (**CS9053**). If a derived type is visible outside the file, its base type must also be visible. However, a non-file-local type *can* implement a file-local interface. +- A file-local type can't be used in a `global using static` directive (**CS9055**). Global usings apply to all files in the compilation, but file-local types are visible only in their declaring file. + +To resolve these errors, either remove the `file` modifier from the type to make it accessible outside the file, or change the consuming code to avoid exposing the file-local type. + +## Declaration rules + +- **CS9054**: *File-local type must be defined in a top level type; it is a nested type.* +- **CS9056**: *Types and aliases cannot be named 'file'.* +- **CS9071**: *The namespace already contains a definition for the type in this file.* + +The compiler enforces rules about how file-local types are declared: + +- File-local types must be declared at the top level of a file, not nested within another type (**CS9054**). To resolve this error, move the type declaration outside any containing type, or remove the `file` modifier. +- Types and type aliases can't be named `file` because it's now a contextual keyword (**CS9056**). To resolve this error, rename the type or use `@file` to escape the identifier. +- A file can't declare multiple file-local types with the same name in the same namespace (**CS9071**). Each file-local type must have a unique name within its namespace scope in that file. To resolve this error, rename one of the conflicting types. + +## File path requirements + +- **CS9068**: *File-local type must be declared in a file with a unique path. Path is used in multiple files.* +- **CS9069**: *File-local type cannot be used because the containing file path cannot be converted into the equivalent UTF-8 byte representation.* + +The compiler uses the file path to generate unique internal names for file-local types. This naming scheme enables multiple files to declare file-local types with the same name without conflict: + +- Each file containing file-local types must have a unique path within the compilation (**CS9068**). This error typically occurs with source generators that produce multiple files with the same path. To resolve this error, ensure each generated file has a distinct path. +- The file path must be convertible to UTF-8 encoding (**CS9069**). This error occurs when the file path contains characters that can't be represented in UTF-8. To resolve this error, rename the file or directory to use characters that are valid in UTF-8. + +These errors most commonly affect source generator authors. For more information about using file-local types in source generators, see [file-local types](../keywords/file.md). diff --git a/docs/csharp/language-reference/compiler-messages/using-directive-errors.md b/docs/csharp/language-reference/compiler-messages/using-directive-errors.md index beecded809ec8..c52b701cfc5c9 100644 --- a/docs/csharp/language-reference/compiler-messages/using-directive-errors.md +++ b/docs/csharp/language-reference/compiler-messages/using-directive-errors.md @@ -20,7 +20,6 @@ f1_keywords: - "CS8914" - "CS8915" - "CS8933" - - "CS9055" - "CS9130" - "CS9131" - "CS9132" @@ -45,7 +44,6 @@ helpviewer_keywords: - "CS8914" - "CS8915" - "CS8933" - - "CS9055" - "CS9130" - "CS9131" - "CS9132" @@ -73,7 +71,6 @@ That's be design. The text closely matches the text of the compiler error / warn - [**CS8085**](#restrictions-on-using-aliases): *Error: A 'using static' directive cannot be used to declare an alias.* - [**CS8914**](#global-using-directive): *Error: A global using directive cannot be used in a namespace declaration.* - [**CS8915**](#global-using-directive): *Error: A global using directive must precede all non-global using directives.* -- [**CS9055**](#global-using-directive): *Error: A file-local type cannot be used in a 'global using static' directive.* - [**CS9130**](#restrictions-on-using-aliases): *Error: Using alias cannot be a `ref` type.* - [**CS9131**](#restrictions-on-using-aliases): *Error: Only a using alias can be `unsafe`.* - [**CS9132**](#restrictions-on-using-aliases): *Error: Using alias cannot be a nullable reference type.* diff --git a/docs/csharp/language-reference/includes/initial-version.md b/docs/csharp/language-reference/includes/initial-version.md new file mode 100644 index 0000000000000..74c4384a607ca --- /dev/null +++ b/docs/csharp/language-reference/includes/initial-version.md @@ -0,0 +1,10 @@ +--- +ms.custom: "updateeachrelease" +--- + +The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release. + +The documentation identifies any feature first introduced in the last three versions of the language or in current public previews. + +> [!TIP] +> To find when a feature was first introduced in C#, consult the article on the [C# language version history](../../whats-new/csharp-version-history.md). diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index fb1678d423de9..82aff46850dba 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -644,7 +644,7 @@ items: href: ./compiler-messages/using-directive-errors.md displayName: > CS0105, CS0138, CS0431, CS0432, CS0440, CS0576, CS0687, CS1529, CS1537, CS7000, - CS7007, CS8019, CS8083, CS8085, CS8914, CS8915, CS8933, CS9055, CS9130, CS9131, + CS7007, CS8019, CS8083, CS8085, CS8914, CS8915, CS8933, CS9130, CS9131, CS9132, CS9133, CS9162, CS9163 - name: Using statements and declarations href: ./compiler-messages/using-statement-declaration-errors.md @@ -657,6 +657,10 @@ items: CS9147, CS9148, CS9149, CS9150, CS9151, CS9152, CS9153, CS9154, CS9155, CS9156, CS9157, CS9158, CS9159, CS9160, CS9161, CS9177, CS9178, CS9206, CS9207, CS9231, CS9232, CS9233, CS9234, CS9235, CS9270 + - name: File local types + href: ./compiler-messages/file-local-types.md + displayName: > + CS9051, CS9052, CS9053, CS9054, CS9055, CS9056, CS9068, CS9069, CS9071 - name: static abstract interface members href: ./compiler-messages/static-abstract-interfaces.md displayName: > @@ -1815,6 +1819,8 @@ items: href: ./compiler-messages/cs8411.md - name: CS8422 href: ./compiler-messages/cs8422.md + - name: CS8506 + href: ../misc/cs8506.md - name: CS8515 href: ./compiler-messages/cs8515.md - name: CS8802 diff --git a/docs/csharp/language-reference/tokens/comments.md b/docs/csharp/language-reference/tokens/comments.md index 11247c99acfa1..42e373b4dc60f 100644 --- a/docs/csharp/language-reference/tokens/comments.md +++ b/docs/csharp/language-reference/tokens/comments.md @@ -1,20 +1,24 @@ --- title: "// and /* */ - comments" description: You use \"//\" for single-line comments. You use \"/*\" to start multi-line comments that end with \"*/\". You add comments to explain your code. -ms.date: 12/12/2022 +ms.date: 01/14/2026 --- -# Code comments - `//` and `/*`. `*/` +# Code comments - `//` and `/*` - `*/` -C# supports two different forms of comments. Single line comments start with `//` and end at the end of that line of code. Multiline comments start with `/*` and end with `*/`. The following code shows an example of each: +C# supports two different forms of comments. Single line comments start with `//` and end at the end of that line of code. Multiline comments start with `/*` and end with `*/`. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +The following code shows an example of each form: :::code language="csharp" source="./snippets/comments.cs" id="ExampleComments"::: -The multi-line comment can also be used to insert text in a line of code. Because these comments have an explicit closing character, you can include more executable code after the comment: +You can use a multiline comment to insert text in a line of code. Because these comments have an explicit closing character, you can include more executable code after the comment: :::code language="csharp" source="./snippets/comments.cs" id="InlineComment"::: -The single line comment can appear after executable code on the same line. The comment ends at the end of the text line: +A single line comment can appear after executable code on the same line. The comment ends at the end of the text line: :::code language="csharp" source="./snippets/comments.cs" id="LineEndingComment"::: -Some comments start with three slashes: `///`. *Triple-slash comments* are *XML documentation comments*. The compiler reads these to produce human documentation. You can read more about [XML doc comments](../xmldoc/index.md) in the section on triple-slash comments. +Some comments start with three slashes: `///`. *Triple-slash comments* are *XML documentation comments*. The compiler reads these comments to produce human documentation. You can read more about [XML doc comments](../xmldoc/index.md) in the section on triple-slash comments. diff --git a/docs/csharp/language-reference/tokens/discard.md b/docs/csharp/language-reference/tokens/discard.md index 0755f2811771d..3d10f9766a0f5 100644 --- a/docs/csharp/language-reference/tokens/discard.md +++ b/docs/csharp/language-reference/tokens/discard.md @@ -1,23 +1,25 @@ --- description: "A `_` is a discard, a placeholder for an unused variable in an expression" title: "Discard - _" -ms.date: 12/17/2024 +ms.date: 01/14/2026 --- # Discard - A `_` acts as a placeholder for a variable The `_` character serves as a *discard*, which is a placeholder for an unused variable. -There are two uses for the *discard* token: +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] -1. To declare an unused variable. A discard can't be read or accessed. +Use the *discard* token in two ways: + +1. To declare an unused variable. You can't read or access a discard. - Unused `out` arguments: `var r = M(out int _, out var _, out _);` - Unused lambda expression parameters: `Action _ => WriteMessage();` - Unused deconstruction arguments: `(int _, var answer) = M();` 1. To match any expression in a [discard pattern](../operators/patterns.md#discard-pattern). You can add a `_` pattern to satisfy exhaustiveness requirements. -The `_` token is a valid identifier in C#. The `_` token is interpreted as a discard only when no valid identifier named `_` is found in scope. +The `_` token is a valid identifier in C#. The compiler interprets the `_` token as a discard only when it doesn't find a valid identifier named `_` in scope. -A discard can't be read as a variable. The compiler reports an error if your code reads a discard. The compiler can avoid allocating the storage for a discard in some situations where that is safe. +You can't read a discard as a variable. If your code reads a discard, the compiler reports an error. In some situations, the compiler can avoid allocating storage for a discard when it's safe to do so. ## See also diff --git a/docs/csharp/language-reference/tokens/index.md b/docs/csharp/language-reference/tokens/index.md index d7c8d7c7cdf05..789afa1671853 100644 --- a/docs/csharp/language-reference/tokens/index.md +++ b/docs/csharp/language-reference/tokens/index.md @@ -1,7 +1,7 @@ --- description: "Special Characters - C# Reference" title: "Special Characters" -ms.date: 10/07/2025 +ms.date: 01/14/2026 f1_keywords: - "cs.special characters" - "@$_CSharpKeyword" @@ -13,13 +13,17 @@ helpviewer_keywords: - "$ character (C#)" --- -# C# Special Characters +# C# special characters -Special characters are predefined, contextual characters that modify the program element (a literal string, an identifier, or an attribute name) to which they're prepended. C# supports the following special characters: +Special characters are predefined, contextual characters that modify the program element (a literal string, an identifier, or an attribute name) that follows them. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + +C# supports the following special characters: - [@](./verbatim.md), the verbatim identifier character. - [$](./interpolated.md), the interpolated string character. -- ["""](./raw-string.md), A sequence of three or more `"` characters provides the delimiters for a raw string literal. -- [_](./discard.md), a `_` character represents a *discard*, which is a placeholder for an unused variable. +- ["""](./raw-string.md), a sequence of three or more `"` characters that provides the delimiters for a raw string literal. +- [_](./discard.md), a `_` character that represents a *discard*, which is a placeholder for an unused variable. -This section only includes those tokens that aren't operators. See the [operators](../operators/index.md) section for all operators. +This section only includes tokens that aren't operators. For all operators, see the [operators](../operators/index.md) section. diff --git a/docs/csharp/language-reference/tokens/interpolated.md b/docs/csharp/language-reference/tokens/interpolated.md index 5472f8d2c9722..03ce2a594c3e2 100644 --- a/docs/csharp/language-reference/tokens/interpolated.md +++ b/docs/csharp/language-reference/tokens/interpolated.md @@ -1,7 +1,7 @@ --- title: "$ - string interpolation - format string output" description: String interpolation using the `$` token provides a more readable and convenient syntax to format string output than traditional string composite formatting. -ms.date: 11/18/2025 +ms.date: 01/14/2026 f1_keywords: - "$_CSharpKeyword" - "$" @@ -14,7 +14,9 @@ author: pkulikov # String interpolation using `$` -The `$` character identifies a string literal as an _interpolated string_. An interpolated string is a string literal that might contain _interpolation expressions_. When an interpolated string is resolved to a result string, the compiler replaces items with interpolation expressions by the string representations of the expression results. +Use the `$` character to identify a string literal as an _interpolated string_. An interpolated string is a string literal that might contain _interpolation expressions_. When you resolve an interpolated string to a result string, the compiler replaces items with interpolation expressions by the string representations of the expression results. + +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] String interpolation provides a more readable, convenient syntax to format strings. It's easier to read than [string composite formatting](../../../standard/base-types/composite-formatting.md). The following example uses both features to produce the same output: @@ -24,7 +26,7 @@ You can use an interpolated string to initialize a [constant](../keywords/const. ## Structure of an interpolated string -To identify a string literal as an interpolated string, prepend it with the `$` symbol. You can't have any white space between the `$` and the `"` that starts a string literal. +To make a string literal an interpolated string, add the `$` symbol at the beginning. Don't include any white space between the `$` and the `"` that starts a string literal. The structure of an item with an interpolation expression is as follows: @@ -44,7 +46,7 @@ The following example uses optional formatting components described in the prece :::code language="csharp" source="./snippets/string-interpolation.cs" id="AlignAndSpecifyFormat"::: -You can use new-lines within an interpolation expression to make the expression's code more readable. The following example shows how new-lines can improve the readability of an expression involving [pattern matching](../operators/patterns.md): +To make the code more readable, use new lines within an interpolation expression. The following example shows how new lines can improve the readability of an expression involving [pattern matching](../operators/patterns.md): :::code language="csharp" source="./snippets/string-interpolation.cs" id="MultiLineExpression"::: @@ -94,12 +96,12 @@ If you're new to string interpolation, see the [String interpolation in C#](../. ## Compilation of interpolated strings -The compiler checks if an interpolated string is assigned to a type that satisfies the [_interpolated string handler pattern_](~/_csharplang/proposals/csharp-10.0/improved-interpolated-strings.md#the-handler-pattern). An _interpolated string handler_ is a type that converts the interpolated string into a result string. When an interpolated string has the type `string`, it's processed by the . For the example of a custom interpolated string handler, see the [Write a custom string interpolation handler](../../advanced-topics/performance/interpolated-string-handler.md) tutorial. Use of an interpolated string handler is an advanced scenario, typically required for performance reasons. +The compiler checks if an interpolated string is assigned to a type that satisfies the [_interpolated string handler pattern_](~/_csharplang/proposals/csharp-10.0/improved-interpolated-strings.md#the-handler-pattern). An _interpolated string handler_ is a type that converts the interpolated string into a result string. When an interpolated string has the type `string`, the processes it. For the example of a custom interpolated string handler, see the [Write a custom string interpolation handler](../../advanced-topics/performance/interpolated-string-handler.md) tutorial. Use of an interpolated string handler is an advanced scenario, typically required for performance reasons. > [!NOTE] -> One side effect of interpolated string handlers is that a custom handler, including , might not evaluate all the interpolation expressions within the interpolated string under all conditions. That means side effects of those expressions might not occur. +> One side effect of interpolated string handlers is that a custom handler, including , might not evaluate all the interpolation expressions within the interpolated string under all conditions. That behavior means side effects of those expressions might not occur. -If an interpolated string has the type `string`, it's typically transformed into a method call. The compiler can replace with if the analyzed behavior would be equivalent to concatenation. +If an interpolated string has the type `string`, the compiler typically transforms it into a method call. The compiler can replace with if the analyzed behavior would be equivalent to concatenation. If an interpolated string has the type or , the compiler generates a call to the method. diff --git a/docs/csharp/language-reference/tokens/raw-string.md b/docs/csharp/language-reference/tokens/raw-string.md index 276e812977bb9..fb2dcff11e180 100644 --- a/docs/csharp/language-reference/tokens/raw-string.md +++ b/docs/csharp/language-reference/tokens/raw-string.md @@ -3,7 +3,7 @@ description: "Raw string literals can contain any arbitrary text without the nee title: "Raw string literals - \"\"\"" f1_keywords: - "RawStringLiteral_CSharpKeyword" -ms.date: 11/18/2025 +ms.date: 01/14/2026 --- # Raw string literal text - `"""` in string literals @@ -15,13 +15,15 @@ Raw string literals can span multiple lines: :::code language="csharp" source="./snippets/raw-string-literal.cs" id="MultiLine"::: +[!INCLUDE[csharp-version-note](../includes/initial-version.md)] + The following rules govern the interpretation of a multi-line raw string literal: - The opening quotes must be the last non-whitespace characters on their line, and the closing quotes must be the first non-whitespace characters on their line. - Any whitespace to the left of the closing quotes is removed from all lines of the raw string literal. - Any whitespace following the opening quotes on the same line is ignored. -- Whitespace only lines following the opening quote are included in the string literal. -- If a whitespace precedes the end delimiter on the same line, the exact number and kind of whitespace characters (for example, spaces vs. tabs) must exist at the beginning of each content line. Specifically, a space doesn't match a horizontal tab, and vice versa. +- Whitespace-only lines following the opening quote are included in the string literal. +- If a whitespace character precedes the end delimiter on the same line, the exact number and kind of whitespace characters (for example, spaces vs. tabs) must exist at the beginning of each content line. Specifically, a space doesn't match a horizontal tab, and vice versa. - The newline before the closing quotes isn't included in the literal string. [!INCLUDE[raw-string-tip](../../includes/raw-string-parsing.md)] @@ -36,7 +38,7 @@ If you need to start or end a raw string literal with quote characters, use the Raw string literals can also be combined with [interpolated strings](./interpolated.md#interpolated-raw-string-literals) to embed the `{` and `}` characters in the output string. You use multiple `$` characters in an interpolated raw string literal to embed `{` and `}` characters in the output string without escaping them. -The raw string literal's content must not contain a set of contiguous `"` characters whose length is equal to or greater than the raw string literal delimiter length. For example, the strings `"""" """ """"` and `""""""" """""" """"" """" """ """""""` are well-formed. However, the strings `""" """ """` and `""" """" """` are ill-formed +The raw string literal's content must not contain a set of contiguous `"` characters whose length is equal to or greater than the raw string literal delimiter length. For example, the strings `"""" """ """"` and `""""""" """""" """"" """" """ """""""` are well-formed. However, the strings `""" """ """` and `""" """" """` are ill-formed. ## See also diff --git a/docs/csharp/language-reference/tokens/verbatim.md b/docs/csharp/language-reference/tokens/verbatim.md index a51819136cb3f..2c3cae7e10529 100644 --- a/docs/csharp/language-reference/tokens/verbatim.md +++ b/docs/csharp/language-reference/tokens/verbatim.md @@ -1,7 +1,7 @@ --- description: "Verbatim text using the `@` enables C# keywords to be used as identifiers, or indicates that a string literal should be interpreted verbatim, or to distinguish attribute names" title: "Verbatim text and strings - @" -ms.date: 11/29/2022 +ms.date: 01/14/2026 f1_keywords: - "@_CSharpKeyword" - "@" @@ -11,23 +11,23 @@ helpviewer_keywords: --- # Verbatim text - `@` in variables, attributes, and string literals -The `@` special character serves as a verbatim identifier. You use it in the following ways: +The `@` special character serves as a verbatim identifier. Use it in the following ways: 1. To indicate that a string literal is to be interpreted verbatim. The `@` character in this instance defines a *verbatim string literal*. Simple escape sequences (such as `"\\"` for a backslash), hexadecimal escape sequences (such as `"\x0041"` for an uppercase A), and Unicode escape sequences (such as `"\u0041"` for an uppercase A) are interpreted literally. Only a quote escape sequence (`""`) isn't interpreted literally; it produces one double quotation mark. Additionally, in case of a verbatim [interpolated string](interpolated.md) brace escape sequences (`{{` and `}}`) aren't interpreted literally; they produce single brace characters. The following example defines two identical file paths, one by using a regular string literal and the other by using a verbatim string literal. This is one of the more common uses of verbatim string literals. - [!code-csharp[verbatim2](../../../../samples/snippets/csharp/language-reference/keywords/verbatim1.cs#2)] + :::code language="csharp" source="../../../../samples/snippets/csharp/language-reference/keywords/verbatim1.cs" id="2"::: The following example illustrates the effect of defining a regular string literal and a verbatim string literal that contain identical character sequences. - [!code-csharp[verbatim3](../../../../samples/snippets/csharp/language-reference/keywords/verbatim1.cs#3)] + :::code language="csharp" source="../../../../samples/snippets/csharp/language-reference/keywords/verbatim1.cs" id="3"::: -1. To use C# keywords as identifiers. The `@` character prefixes a code element that the compiler is to interpret as an identifier rather than a C# keyword. The following example uses the `@` character to define an identifier named `for` that it uses in a `for` loop. +1. To use C# keywords as identifiers. The `@` character prefixes a code element that the compiler interprets as an identifier rather than a C# keyword. The following example uses the `@` character to define an identifier named `for` that it uses in a `for` loop. - [!code-csharp[verbatim1](../../../../samples/snippets/csharp/language-reference/keywords/verbatim1.cs#1)] + :::code language="csharp" source="../../../../samples/snippets/csharp/language-reference/keywords/verbatim1.cs" id="1"::: -1. To enable the compiler to distinguish between attributes in cases of a naming conflict. An attribute is a class that derives from . Its type name typically includes the suffix **Attribute**, although the compiler doesn't enforce this convention. The attribute can then be referenced in code either by its full type name (for example, `[InfoAttribute]` or its shortened name (for example, `[Info]`). However, a naming conflict occurs if two shortened attribute type names are identical, and one type name includes the **Attribute** suffix but the other doesn't. For example, the following code fails to compile because the compiler can't determine whether the `Info` or `InfoAttribute` attribute is applied to the `Example` class. For more information, see [CS1614](../compiler-messages/cs1614.md). +1. To enable the compiler to distinguish between attributes in cases of a naming conflict. An attribute is a class that derives from . Its type name typically includes the suffix **Attribute**, although the compiler doesn't enforce this convention. You can reference the attribute in code either by its full type name (for example, `[InfoAttribute]`) or by its shortened name (for example, `[Info]`). However, a naming conflict occurs if two shortened attribute type names are identical, and one type name includes the **Attribute** suffix but the other doesn't. For example, the following code fails to compile because the compiler can't determine whether the `Info` or `InfoAttribute` attribute is applied to the `Example` class. For more information, see [CS1614](../compiler-messages/cs1614.md). - [!code-csharp[verbatim4](../../../../samples/snippets/csharp/language-reference/keywords/verbatim2.cs#1)] + :::code language="csharp" source="../../../../samples/snippets/csharp/language-reference/keywords/verbatim2.cs" id="1"::: ## See also diff --git a/docs/csharp/misc/cs8506.md b/docs/csharp/misc/cs8506.md new file mode 100644 index 0000000000000..302cb3ded62e0 --- /dev/null +++ b/docs/csharp/misc/cs8506.md @@ -0,0 +1,58 @@ +--- +description: "Learn more about: Compiler Error CS8506" +title: "Compiler Error CS8506" +ms.date: 01/13/2026 +f1_keywords: + - "CS8506" +helpviewer_keywords: + - "CS8506" +--- + +# Compiler Error CS8506 + +No best type was found for the switch expression. + +Compiler is unable to deduce the type of return value or expression based on the existing implementation. + +## Example + +The following sample generates CS8500: + +```csharp +static void MethodA(int param) { } +static void MethodB(int param) { } + +var parameter = 4; + +var ActionMethod = parameter switch // CS8506 +{ + 1 => MethodA, + _ => MethodB, +}; +``` + +In the example above the `CS8506` is reported, because compiler can't deduce type of ActionMethod only by type of `MethodA` and `MethodB`. + +## To correct this error + +The solution is to specify the type explicitly: + +```csharp +static void MethodA(int param) { } +static void MethodB(int param) { } + +var parameter = 4; + +Action ActionMethod = parameter switch +{ + 1 => MethodA, + _ => MethodB, +}; + +delegate void Action(int param); +``` + +## See also + +- [switch expression](../language-reference/operators/switch-expression.md) +- [delegate](../programming-guide/delegates/index.md) 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 3dd51d857228a..9b760c8339497 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 @@ -299,7 +299,6 @@ f1_keywords: - "CS8503" - "CS8504" - "CS8505" - - "CS8506" - "CS8508" - "CS8510" - "CS8512" @@ -457,17 +456,8 @@ f1_keywords: - "CS9044" - "CS9046" - "CS9049" - - "CS9051" - - "CS9052" - - "CS9053" - - "CS9054" - - "CS9056" - - "CS9058" - "CS9064" - "CS9067" - - "CS9068" - - "CS9070" - - "CS9071" helpviewer_keywords: - "errors [C#], additional information" --- diff --git a/docs/csharp/tour-of-csharp/snippets/file-based-programs/hello-world.cs b/docs/csharp/tour-of-csharp/snippets/file-based-programs/hello-world.cs index e3173e7a15eb4..f1b4d0978a721 100755 --- a/docs/csharp/tour-of-csharp/snippets/file-based-programs/hello-world.cs +++ b/docs/csharp/tour-of-csharp/snippets/file-based-programs/hello-world.cs @@ -1,2 +1,3 @@ -#!/usr/local/share/dotnet/dotnet run +#!/usr/bin/env dotnet + Console.WriteLine("Hello, World!"); diff --git a/docs/csharp/tour-of-csharp/tutorials/snippets/PatternMatching/patterns.cs b/docs/csharp/tour-of-csharp/tutorials/snippets/PatternMatching/patterns.cs index 516a8bb2e8359..50bca40bb0c40 100644 --- a/docs/csharp/tour-of-csharp/tutorials/snippets/PatternMatching/patterns.cs +++ b/docs/csharp/tour-of-csharp/tutorials/snippets/PatternMatching/patterns.cs @@ -133,7 +133,6 @@ else if (transactionType?.ToUpper() is "WITHDRAWAL") yield return new Withdrawal(amount, parts[2]); } - yield return default; } } // diff --git a/docs/framework/app-domains/how-to-load-assemblies-into-an-application-domain.md b/docs/framework/app-domains/how-to-load-assemblies-into-an-application-domain.md index 88828436f7762..9dd5155458676 100644 --- a/docs/framework/app-domains/how-to-load-assemblies-into-an-application-domain.md +++ b/docs/framework/app-domains/how-to-load-assemblies-into-an-application-domain.md @@ -47,7 +47,7 @@ There are several ways to load an assembly into an application domain. The recom - - [Programming with Application Domains](application-domains.md#programming-with-application-domains) -- [Reflection](../../fundamentals/reflection/reflection.md) +- [Reflection](../../fundamentals/reflection/overview.md) - [Using Application Domains](use.md) - [How to: Load Assemblies into the Reflection-Only Context](../reflection-and-codedom/how-to-load-assemblies-into-the-reflection-only-context.md) - [Application domains and assemblies](application-domains.md#application-domains-and-assemblies) diff --git a/docs/framework/app-domains/index.md b/docs/framework/app-domains/index.md index 0d8cf21391689..d51701d276736 100644 --- a/docs/framework/app-domains/index.md +++ b/docs/framework/app-domains/index.md @@ -36,5 +36,5 @@ Provides a conceptual overview of assemblies. [Application Domains](application-domains.md)\ Provides a conceptual overview of application domains. -[Reflection Overview](../../fundamentals/reflection/reflection.md)\ +[Reflection Overview](../../fundamentals/reflection/overview.md)\ Describes how to use the `Reflection` class to obtain information about an assembly. diff --git a/docs/framework/app-domains/use.md b/docs/framework/app-domains/use.md index 41ee28a5d6792..35c59ead53339 100644 --- a/docs/framework/app-domains/use.md +++ b/docs/framework/app-domains/use.md @@ -64,5 +64,5 @@ Describes how to create dynamic assemblies. [Application Domains](application-domains.md) Provides a conceptual overview of application domains. -[Reflection Overview](../../fundamentals/reflection/reflection.md) +[Reflection Overview](../../fundamentals/reflection/overview.md) Describes how to use the `Reflection` class to obtain information about an assembly. diff --git a/docs/framework/reflection-and-codedom/reflection-for-windows-store-apps.md b/docs/framework/reflection-and-codedom/reflection-for-windows-store-apps.md index 0518c048c459d..b3cdaed4ff289 100644 --- a/docs/framework/reflection-and-codedom/reflection-for-windows-store-apps.md +++ b/docs/framework/reflection-and-codedom/reflection-for-windows-store-apps.md @@ -41,4 +41,4 @@ Starting with .NET Framework 4.5, the .NET Framework includes a set of reflectio ## See also -- [Reflection](../../fundamentals/reflection/reflection.md) +- [Reflection](../../fundamentals/reflection/overview.md) diff --git a/docs/framework/reflection-and-codedom/toc.yml b/docs/framework/reflection-and-codedom/toc.yml index 575545332b6b7..d569179372eb2 100644 --- a/docs/framework/reflection-and-codedom/toc.yml +++ b/docs/framework/reflection-and-codedom/toc.yml @@ -2,7 +2,7 @@ items: - name: Reflection items: - name: Overview - href: ../../fundamentals/reflection/reflection.md?toc=/dotnet/framework/reflection-and-codedom/toc.json&bc=/dotnet/breadcrumb/toc.json + href: ../../fundamentals/reflection/overview.md?toc=/dotnet/framework/reflection-and-codedom/toc.json&bc=/dotnet/breadcrumb/toc.json - name: Security Considerations for Reflection href: security-considerations-for-reflection.md - name: "How to: Load Assemblies into the Reflection-Only Context" diff --git a/docs/fsharp/language-reference/strings.md b/docs/fsharp/language-reference/strings.md index c2a6f9dbc6718..a6b331dec8c2f 100644 --- a/docs/fsharp/language-reference/strings.md +++ b/docs/fsharp/language-reference/strings.md @@ -50,7 +50,7 @@ let xmlFragment1 = @"" let xmlFragment2 = """""" ``` -In code, strings that have line breaks are accepted and the line breaks are interpreted as the newline encoding used in source, unless a backslash character is the last character before the line break. Leading white space on the next line is ignored when the backslash character is used. The following code produces a string `str1` that has value `"abc\ndef"` and a string `str2` that has value `"abcdef"`. +In code, strings that have line breaks are accepted and the line breaks are interpreted as the newline encoding used in source, unless a backslash character is the last character before the line break. Leading white space on the next line is ignored when the backslash character is used. The following code produces a string `str1` that has value `"abc\n def"` and a string `str2` that has value `"abcdef"`. [!code-fsharp[Main](~/samples/snippets/fsharp/lang-ref-1/snippet1001.fs)] diff --git a/docs/fundamentals/code-analysis/quality-rules/ca2264.md b/docs/fundamentals/code-analysis/quality-rules/ca2264.md index 7b065e3dc5ca6..8f33281532fd4 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca2264.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca2264.md @@ -22,11 +22,11 @@ dev_langs: ## Cause -When a value that's known to never be null is passed to `ArgumentNullException.ThrowIfNull()`, an exception is never thrown, making the statement a no-op. +A value that's known to never be null is passed to `ArgumentNullException.ThrowIfNull()`. ## Rule description -`ArgumentNullException.ThrowIfNull` throws when the passed argument is `null`. Certain constructs like non-nullable structs (except for ), type parameters known to be non-nullable structs, 'nameof()' expressions, and 'new' expressions are known to never be null, so `ArgumentNullException.ThrowIfNull` will never throw. +`ArgumentNullException.ThrowIfNull` throws when the passed argument is `null`. Certain constructs like non-nullable structs (except for ), type parameters known to be non-nullable structs, 'nameof()' expressions, and 'new' expressions are known to never be null, so `ArgumentNullException.ThrowIfNull` will never throw. Thus, calling `ArgumentNullException.ThrowIfNull` is unnecessary. In the case of a struct, since `ArgumentNullException.ThrowIfNull` accepts an `object?`, the struct is boxed, which causes an additional performance penalty. @@ -77,3 +77,7 @@ dotnet_diagnostic.CA2264.severity = none ``` For more information, see [How to suppress code analysis warnings](../suppress-warnings.md). + +## See also + +- [CA1871: Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull](ca1871.md) diff --git a/docs/fundamentals/reflection/dynamically-loading-and-using-types.md b/docs/fundamentals/reflection/dynamically-loading-and-using-types.md index 54610c6a9f471..ee531bac4d2fb 100644 --- a/docs/fundamentals/reflection/dynamically-loading-and-using-types.md +++ b/docs/fundamentals/reflection/dynamically-loading-and-using-types.md @@ -72,21 +72,21 @@ In Case 3 of the code example, an actual argument of type `String` with a value `ChangeType` performs only lossless or [widening coercions](../../standard/base-types/type-conversion.md), as shown in the following table. -| Source type | Target type | -| ----------------- | ----------------------------------------------------------------- | -| Any type | Its base type | -| Any type | Interface it implements | -| Char | UInt16, UInt32, Int32, UInt64, Int64, Single, Double | -| Byte | Char, UInt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double | -| SByte | Int16, Int32, Int64, Single, Double | -| UInt16 | UInt32, Int32, UInt64, Int64, Single, Double | -| Int16 | Int32, Int64, Single, Double | -| UInt32 | UInt64, Int64, Single, Double | -| Int32 | Int64, Single, Double | -| UInt64 | Single, Double | -| Int64 | Single, Double | -| Single | Double | -| Nonreference type | Reference type | +| Source type | Target type | +|-------------|-------------------------------------------------------------------------------------| +| Any type | Its base type | +| Any type | The interface it implements | +| `Char` | `UInt16`, `UInt32`, `Int32`, `UInt64`, `Int64`, `Single`, `Double` | +| `Byte` | `Char`, `UInt16`, `Int16`, `UInt32`, `Int32`, `UInt64`, `Int64`, `Single`, `Double` | +| `SByte` | `Int16`, `Int32`, `Int64`, `Single`, `Double` | +| `UInt16` | `UInt32`, `Int32`, `UInt64`, `Int64`, `Single`, `Double` | +| `Int16` | `Int32`, `Int64`, `Single`, `Double` | +| `UInt32` | `UInt64`, `Int64`, `Single`, `Double` | +| `Int32` | `Int64`, `Single`, `Double` | +| `UInt64` | `Single`, `Double` | +| `Int64` | `Single`, `Double` | +| `Single` | `Double` | +| Nonreference type | Reference type | The class has `Get` methods that use parameters of type `Binder` to resolve references to a particular member. , , and search for a particular member of the current type by providing signature information for that member. and are called back on to select the given signature information of the appropriate methods. diff --git a/docs/fundamentals/reflection/get-type-member-information.md b/docs/fundamentals/reflection/get-type-member-information.md index b1c83e1c36eef..4d6142e6cce1a 100644 --- a/docs/fundamentals/reflection/get-type-member-information.md +++ b/docs/fundamentals/reflection/get-type-member-information.md @@ -12,7 +12,7 @@ dev_langs: --- # How to: Get type and member information by using reflection -The namespace contains many methods for obtaining information about types and their members. This article demonstrates one of these methods, . For additional information, see [Reflection overview](reflection.md). +The namespace contains many methods for obtaining information about types and their members. This article demonstrates one of these methods, . For additional information, see [Reflection overview](overview.md). ## Example @@ -23,4 +23,4 @@ The following example obtains type and member information by using reflection: ## See also -- [Reflection](reflection.md) +- [Reflection](overview.md) diff --git a/docs/fundamentals/reflection/how-to-define-a-generic-method-with-reflection-emit.md b/docs/fundamentals/reflection/how-to-define-a-generic-method-with-reflection-emit.md index 8b566236ab4de..2d863095664ae 100644 --- a/docs/fundamentals/reflection/how-to-define-a-generic-method-with-reflection-emit.md +++ b/docs/fundamentals/reflection/how-to-define-a-generic-method-with-reflection-emit.md @@ -1,5 +1,6 @@ --- -title: "How to: Define a Generic Method with Reflection Emit" +title: "How to: Define a Generic Method with Reflection Emit (.NET Framework)" +titleSuffix: "" description: Define a generic method with reflection emit. One example creates a generic method with two type parameters. A second example shows how to emit the method body. ms.date: 03/27/2024 dev_langs: @@ -9,9 +10,11 @@ helpviewer_keywords: - "generics [.NET], reflection emit" - "reflection emit, generic methods" - "generics [.NET], dynamic types" -ms.assetid: 93892fa4-90b3-4ec4-b147-4bec9880de2b --- -# How to: Define a generic method with reflection emit +# How to: Define a generic method with reflection emit (.NET Framework) + +> [!IMPORTANT] +> This how-to article shows .NET Framework-specific APIs that aren't available in modern .NET. To save a dynamic assembly to disk in modern .NET, use the type. The first procedure shows how to create a simple generic method with two type parameters, and how to apply class constraints, interface constraints, and special constraints to the type parameters. @@ -26,47 +29,47 @@ The third procedure shows how to invoke the generic method. 1. Before beginning, it is useful to look at how the generic method appears when written using a high-level language. The following code is included in the example code for this article, along with code to call the generic method. The method has two type parameters, `TInput` and `TOutput`, the second of which must be a reference type (`class`), must have a parameterless constructor (`new`), and must implement `ICollection`. This interface constraint ensures that the method can be used to add elements to the `TOutput` collection that the method creates. The method has one formal parameter, `input`, which is an array of `TInput`. The method creates a collection of type `TOutput` and copies the elements of `input` to the collection. - [!code-csharp[GenericMethodHowTo#20](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#20)] + [!code-csharp[GenericMethodHowTo#20](./snippets/csharp/construct-generic-method/source.cs#20)] [!code-vb[GenericMethodHowTo#20](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#20)] 1. Define a dynamic assembly and a dynamic module to contain the type the generic method belongs to. In this case, the assembly has only one module, named `DemoMethodBuilder1`, and the module name is the same as the assembly name plus an extension. In this example, the assembly is saved to disk and also executed, so is specified. You can use the [Ildasm.exe (IL Disassembler)](../../framework/tools/ildasm-exe-il-disassembler.md) to examine DemoMethodBuilder1.dll and to compare it to the common intermediate language (CIL) for the method shown in step 1. - [!code-csharp[GenericMethodHowTo#2](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#2)] + [!code-csharp[GenericMethodHowTo#2](./snippets/csharp/construct-generic-method/source.cs#2)] [!code-vb[GenericMethodHowTo#2](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#2)] 1. Define the type the generic method belongs to. The type does not have to be generic. A generic method can belong to either a generic or nongeneric type. In this example, the type is a class, is not generic, and is named `DemoType`. - [!code-csharp[GenericMethodHowTo#3](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#3)] + [!code-csharp[GenericMethodHowTo#3](./snippets/csharp/construct-generic-method/source.cs#3)] [!code-vb[GenericMethodHowTo#3](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#3)] 1. Define the generic method. If the types of a generic method's formal parameters are specified by generic type parameters of the generic method, use the method overload to define the method. The generic type parameters of the method are not yet defined, so you cannot specify the types of the method's formal parameters in the call to . In this example, the method is named `Factory`. The method is public and `static` (`Shared` in Visual Basic). - [!code-csharp[GenericMethodHowTo#4](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#4)] + [!code-csharp[GenericMethodHowTo#4](./snippets/csharp/construct-generic-method/source.cs#4)] [!code-vb[GenericMethodHowTo#4](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#4)] 1. Define the generic type parameters of `DemoMethod` by passing an array of strings containing the names of the parameters to the method. This makes the method a generic method. The following code makes `Factory` a generic method with type parameters `TInput` and `TOutput`. To make the code easier to read, variables with these names are created to hold the objects representing the two type parameters. - [!code-csharp[GenericMethodHowTo#5](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#5)] + [!code-csharp[GenericMethodHowTo#5](./snippets/csharp/construct-generic-method/source.cs#5)] [!code-vb[GenericMethodHowTo#5](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#5)] 1. Optionally add special constraints to the type parameters. Special constraints are added using the method. In this example, `TOutput` is constrained to be a reference type and to have a parameterless constructor. - [!code-csharp[GenericMethodHowTo#6](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#6)] + [!code-csharp[GenericMethodHowTo#6](./snippets/csharp/construct-generic-method/source.cs#6)] [!code-vb[GenericMethodHowTo#6](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#6)] 1. Optionally add class and interface constraints to the type parameters. In this example, type parameter `TOutput` is constrained to types that implement the `ICollection(Of TInput)` (`ICollection` in C#) interface. This ensures that the method can be used to add elements. - [!code-csharp[GenericMethodHowTo#7](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#7)] + [!code-csharp[GenericMethodHowTo#7](./snippets/csharp/construct-generic-method/source.cs#7)] [!code-vb[GenericMethodHowTo#7](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#7)] 1. Define the formal parameters of the method, using the method. In this example, the `Factory` method has one parameter, an array of `TInput`. This type is created by calling the method on the that represents `TInput`. The argument of is an array of objects. - [!code-csharp[GenericMethodHowTo#8](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#8)] + [!code-csharp[GenericMethodHowTo#8](./snippets/csharp/construct-generic-method/source.cs#8)] [!code-vb[GenericMethodHowTo#8](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#8)] 1. Define the return type for the method, using the method. In this example, an instance of `TOutput` is returned. - [!code-csharp[GenericMethodHowTo#9](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#9)] + [!code-csharp[GenericMethodHowTo#9](./snippets/csharp/construct-generic-method/source.cs#9)] [!code-vb[GenericMethodHowTo#9](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#9)] 1. Emit the method body, using . For details, see the accompanying procedure for emitting the method body. @@ -76,7 +79,7 @@ The third procedure shows how to invoke the generic method. 1. Complete the type that contains the method and save the assembly. The accompanying procedure for invoking the generic method shows two ways to invoke the completed method. - [!code-csharp[GenericMethodHowTo#14](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#14)] + [!code-csharp[GenericMethodHowTo#14](./snippets/csharp/construct-generic-method/source.cs#14)] [!code-vb[GenericMethodHowTo#14](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#14)] ## Emit the method body @@ -85,56 +88,56 @@ The third procedure shows how to invoke the generic method. The first thing the method does is to load its argument using opcode and to store it in the local variable `input` using opcode. - [!code-csharp[GenericMethodHowTo#10](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#10)] + [!code-csharp[GenericMethodHowTo#10](./snippets/csharp/construct-generic-method/source.cs#10)] [!code-vb[GenericMethodHowTo#10](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#10)] 2. Emit code to create an instance of `TOutput`, using the generic method overload of the method. Using this overload requires the specified type to have a parameterless constructor, which is the reason for adding that constraint to `TOutput`. Create the constructed generic method by passing `TOutput` to . After emitting code to call the method, emit code to store it in the local variable `retVal` using - [!code-csharp[GenericMethodHowTo#11](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#11)] + [!code-csharp[GenericMethodHowTo#11](./snippets/csharp/construct-generic-method/source.cs#11)] [!code-vb[GenericMethodHowTo#11](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#11)] 3. Emit code to cast the new `TOutput` object to `ICollection(Of TInput)` and store it in the local variable `ic`. - [!code-csharp[GenericMethodHowTo#31](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#31)] + [!code-csharp[GenericMethodHowTo#31](./snippets/csharp/construct-generic-method/source.cs#31)] [!code-vb[GenericMethodHowTo#31](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#31)] 4. Get a representing the method. The method is acting on an `ICollection`, so it's necessary to get the `Add` method specific to that constructed type. You cannot use the method to get this directly from `icollOfTInput`, because is not supported on a type that has been constructed with a . Instead, call on `icoll`, which contains the generic type definition for the generic interface. Then use the `static` method to produce the for the constructed type. The following code demonstrates this. - [!code-csharp[GenericMethodHowTo#12](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#12)] + [!code-csharp[GenericMethodHowTo#12](./snippets/csharp/construct-generic-method/source.cs#12)] [!code-vb[GenericMethodHowTo#12](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#12)] 5. Emit code to initialize the `index` variable, by loading a 32-bit integer 0 and storing it in the variable. Emit code to branch to the label `enterLoop`. This label has not yet been marked, because it is inside the loop. Code for the loop is emitted in the next step. - [!code-csharp[GenericMethodHowTo#32](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#32)] + [!code-csharp[GenericMethodHowTo#32](./snippets/csharp/construct-generic-method/source.cs#32)] [!code-vb[GenericMethodHowTo#32](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#32)] 6. Emit code for the loop. The first step is to mark the top of the loop, by calling with the `loopAgain` label. Branch statements that use the label will now branch to this point in the code. The next step is to push the `TOutput` object, cast to `ICollection(Of TInput)`, onto the stack. It is not needed immediately, but needs to be in position for calling the `Add` method. Next the input array is pushed onto the stack, then the `index` variable containing the current index into the array. The opcode pops the index and the array off the stack and pushes the indexed array element onto the stack. The stack is now ready for the call to the method, which pops the collection and the new element off the stack and adds the element to the collection. The rest of the code in the loop increments the index and tests to see whether the loop is finished: The index and a 32-bit integer 1 are pushed onto the stack and added, leaving the sum on the stack; the sum is stored in `index`. is called to set this point as the entry point for the loop. The index is loaded again. The input array is pushed on the stack, and is emitted to get its length. The index and the length are now on the stack, and is emitted to compare them. If the index is less than the length, branches back to the beginning of the loop. - [!code-csharp[GenericMethodHowTo#13](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#13)] + [!code-csharp[GenericMethodHowTo#13](./snippets/csharp/construct-generic-method/source.cs#13)] [!code-vb[GenericMethodHowTo#13](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#13)] 7. Emit code to push the `TOutput` object onto the stack and return from the method. The local variables `retVal` and `ic` both contain references to the new `TOutput`; `ic` is used only to access the method. - [!code-csharp[GenericMethodHowTo#33](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#33)] + [!code-csharp[GenericMethodHowTo#33](./snippets/csharp/construct-generic-method/source.cs#33)] [!code-vb[GenericMethodHowTo#33](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#33)] ## Invoke the generic method 1. `Factory` is a generic method definition. In order to invoke it, you must assign types to its generic type parameters. Use the method to do this. The following code creates a constructed generic method, specifying for `TInput` and `List(Of String)` (`List` in C#) for `TOutput`, and displays a string representation of the method. - [!code-csharp[GenericMethodHowTo#21](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#21)] + [!code-csharp[GenericMethodHowTo#21](./snippets/csharp/construct-generic-method/source.cs#21)] [!code-vb[GenericMethodHowTo#21](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#21)] 2. To invoke the method late-bound, use the method. The following code creates an array of , containing as its only element an array of strings, and passes it as the argument list for the generic method. The first parameter of is a null reference because the method is `static`. The return value is cast to `List(Of String)`, and its first element is displayed. - [!code-csharp[GenericMethodHowTo#22](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#22)] + [!code-csharp[GenericMethodHowTo#22](./snippets/csharp/construct-generic-method/source.cs#22)] [!code-vb[GenericMethodHowTo#22](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#22)] 3. To invoke the method using a delegate, you must have a delegate that matches the signature of the constructed generic method. An easy way to do this is to create a generic delegate. The following code creates an instance of the generic delegate `D` defined in the example code, using the method overload, and invokes the delegate. Delegates perform better than late-bound calls. - [!code-csharp[GenericMethodHowTo#23](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#23)] + [!code-csharp[GenericMethodHowTo#23](./snippets/csharp/construct-generic-method/source.cs#23)] [!code-vb[GenericMethodHowTo#23](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#23)] 4. The emitted method can also be called from a program that refers to the saved assembly. @@ -152,7 +155,7 @@ When the code is executed, the dynamic assembly is saved as DemoGenericMethod1.d The code example includes source code that's equivalent to the emitted method. The emitted method is invoked late-bound and also by using a generic delegate declared in the code example. -[!code-csharp[GenericMethodHowTo#1](../../../samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs#1)] +[!code-csharp[GenericMethodHowTo#1](./snippets/csharp/construct-generic-method/source.cs#1)] [!code-vb[GenericMethodHowTo#1](../../../samples/snippets/visualbasic/VS_Snippets_CLR/GenericMethodHowTo/VB/source.vb#1)] ## See also diff --git a/docs/fundamentals/reflection/how-to-define-a-generic-type-with-reflection-emit.md b/docs/fundamentals/reflection/how-to-define-a-generic-type-with-reflection-emit.md index ab135521f8f2e..fd2374abd662d 100644 --- a/docs/fundamentals/reflection/how-to-define-a-generic-type-with-reflection-emit.md +++ b/docs/fundamentals/reflection/how-to-define-a-generic-type-with-reflection-emit.md @@ -1,7 +1,8 @@ --- -title: "How to: Define a Generic Type with Reflection Emit" -description: See how to define a generic type with reflection emit. Create a generic type with two type parameters, apply class constraints, interface constraints, and more. -ms.date: 03/27/2024 +title: "How to: Define a Generic Type with Reflection Emit (.NET Framework)" +titleSuffix: "" +description: Learn how to define a generic type with reflection emit. Create a generic type with two type parameters, apply class constraints, interface constraints, and more. +ms.date: 01/09/2026 dev_langs: - "csharp" - "vb" @@ -10,9 +11,16 @@ helpviewer_keywords: - "generics [.NET], dynamic types" - "reflection emit, generic types" --- -# How to: Define a generic type with reflection emit +# How to: Define a generic type with reflection emit (.NET Framework) -This article shows how to create a simple generic type with two type parameters, how to apply class constraints, interface constraints, and special constraints to the type parameters, and how to create members that use the type parameters of the class as parameter types and return types. +> [!IMPORTANT] +> This how-to article shows .NET Framework-specific APIs that aren't available in modern .NET. To save a dynamic assembly to disk in modern .NET, use the type. + +This article shows you how to: + +- Create a simple generic type with two type parameters. +- Apply class constraints, interface constraints, and special constraints to the type parameters. +- Create members that use the type parameters of the class as parameter types and return types. > [!IMPORTANT] > A method is not generic just because it belongs to a generic type and uses the type parameters of that type. A method is generic only if it has its own type parameter list. Most methods on generic types are not generic, as in this example. For an example of emitting a generic method, see [How to: Define a Generic Method with Reflection Emit](how-to-define-a-generic-method-with-reflection-emit.md). @@ -21,44 +29,44 @@ This article shows how to create a simple generic type with two type parameters, 1. Define a dynamic assembly named `GenericEmitExample1`. In this example, the assembly is executed and saved to disk, so is specified. - [!code-csharp[EmitGenericType#2](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#2)] + [!code-csharp[EmitGenericType#2](./snippets/csharp/emit-generic-type/source.cs#2)] [!code-vb[EmitGenericType#2](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#2)] 1. Define a dynamic module. An assembly is made up of executable modules. For a single-module assembly, the module name is the same as the assembly name, and the file name is the module name plus an extension. - [!code-csharp[EmitGenericType#3](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#3)] + [!code-csharp[EmitGenericType#3](./snippets/csharp/emit-generic-type/source.cs#3)] [!code-vb[EmitGenericType#3](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#3)] 1. Define a class. In this example, the class is named `Sample`. - [!code-csharp[EmitGenericType#4](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#4)] + [!code-csharp[EmitGenericType#4](./snippets/csharp/emit-generic-type/source.cs#4)] [!code-vb[EmitGenericType#4](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#4)] 1. Define the generic type parameters of `Sample` by passing an array of strings containing the names of the parameters to the method. This makes the class a generic type. The return value is an array of objects representing the type parameters, which can be used in your emitted code. In the following code, `Sample` becomes a generic type with type parameters `TFirst` and `TSecond`. To make the code easier to read, each is placed in a variable with the same name as the type parameter. - [!code-csharp[EmitGenericType#5](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#5)] + [!code-csharp[EmitGenericType#5](./snippets/csharp/emit-generic-type/source.cs#5)] [!code-vb[EmitGenericType#5](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#5)] 1. Add special constraints to the type parameters. In this example, type parameter `TFirst` is constrained to types that have parameterless constructors, and to reference types. - [!code-csharp[EmitGenericType#6](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#6)] + [!code-csharp[EmitGenericType#6](./snippets/csharp/emit-generic-type/source.cs#6)] [!code-vb[EmitGenericType#6](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#6)] 1. Optionally add class and interface constraints to the type parameters. In this example, type parameter `TFirst` is constrained to types that derive from the base class represented by the object contained in the variable `baseType`, and that implement the interfaces whose types are contained in the variables `interfaceA` and `interfaceB`. See the code example for the declaration and assignment of these variables. - [!code-csharp[EmitGenericType#7](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#7)] + [!code-csharp[EmitGenericType#7](./snippets/csharp/emit-generic-type/source.cs#7)] [!code-vb[EmitGenericType#7](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#7)] 1. Define a field. In this example, the type of the field is specified by type parameter `TFirst`. derives from , so you can use generic type parameters anywhere a type can be used. - [!code-csharp[EmitGenericType#21](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#21)] + [!code-csharp[EmitGenericType#21](./snippets/csharp/emit-generic-type/source.cs#21)] [!code-vb[EmitGenericType#21](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#21)] 1. Define a method that uses the type parameters of the generic type. Note that such methods are not generic unless they have their own type parameter lists. The following code defines a `static` method (`Shared` in Visual Basic) that takes an array of `TFirst` and returns a `List` (`List(Of TFirst)` in Visual Basic) containing all the elements of the array. To define this method, it is necessary to create the type `List` by calling on the generic type definition, `List`. (The `T` is omitted when you use the `typeof` operator (`GetType` in Visual Basic) to get the generic type definition.) The parameter type is created by using the method. - [!code-csharp[EmitGenericType#22](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#22)] + [!code-csharp[EmitGenericType#22](./snippets/csharp/emit-generic-type/source.cs#22)] [!code-vb[EmitGenericType#22](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#22)] 1. Emit the method body. The method body consists of three opcodes that load the input array onto the stack, call the `List` constructor that takes `IEnumerable` (which does all the work of putting the input elements into the list), and return (leaving the new object on the stack). The difficult part of emitting this code is getting the constructor. @@ -72,27 +80,27 @@ This article shows how to create a simple generic type with two type parameters, Now it is possible to get the constructor of `List` by calling on the generic type definition. To convert this constructor to the corresponding constructor of `List`, pass `List` and the constructor from `List` to the static method. - [!code-csharp[EmitGenericType#23](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#23)] + [!code-csharp[EmitGenericType#23](./snippets/csharp/emit-generic-type/source.cs#23)] [!code-vb[EmitGenericType#23](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#23)] 1. Create the type and save the file. - [!code-csharp[EmitGenericType#8](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#8)] + [!code-csharp[EmitGenericType#8](./snippets/csharp/emit-generic-type/source.cs#8)] [!code-vb[EmitGenericType#8](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#8)] 1. Invoke the method. `ExampleMethod` is not generic, but the type it belongs to is generic, so to get a that can be invoked, it's necessary to create a constructed type from the type definition for `Sample`. The constructed type uses the `Example` class, which satisfies the constraints on `TFirst` because it is a reference type and has a default parameterless constructor, and the `ExampleDerived` class which satisfies the constraints on `TSecond`. (The code for `ExampleDerived` can be found in the example code section.) These two types are passed to to create the constructed type. The is then obtained using the method. - [!code-csharp[EmitGenericType#9](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#9)] + [!code-csharp[EmitGenericType#9](./snippets/csharp/emit-generic-type/source.cs#9)] [!code-vb[EmitGenericType#9](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#9)] 1. The following code creates an array of `Example` objects, places that array in an array of type representing the arguments of the method to be invoked, and passes them to the method. The first argument of the method is a null reference because the method is `static`. - [!code-csharp[EmitGenericType#10](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#10)] + [!code-csharp[EmitGenericType#10](./snippets/csharp/emit-generic-type/source.cs#10)] [!code-vb[EmitGenericType#10](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#10)] ## Example -The following code example defines a class named `Sample`, along with a base class and two interfaces. The program defines two generic type parameters for `Sample`, turning it into a generic type. Type parameters are the only thing that makes a type generic. The program shows this by displaying a test message before and after the definition of the type parameters. +The following code example shows the full program. It defines a class named `Sample`, along with a base class and two interfaces. The program defines two generic type parameters for `Sample`, turning it into a generic type. Type parameters are the only thing that makes a type generic. The program shows this by displaying a test message before and after the definition of the type parameters. The type parameter `TSecond` is used to demonstrate class and interface constraints, using the base class and interfaces, and the type parameter `TFirst` is used to demonstrate special constraints. @@ -104,7 +112,7 @@ The program includes a method that lists information about a generic type, and a The program saves the finished module to disk as `GenericEmitExample1.dll`, so you can open it with the [Ildasm.exe (IL Disassembler)](../../framework/tools/ildasm-exe-il-disassembler.md) and examine the CIL for the `Sample` class. -[!code-csharp[EmitGenericType#1](../../../samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs#1)] +[!code-csharp[EmitGenericType#1](./snippets/csharp/emit-generic-type/source.cs#1)] [!code-vb[EmitGenericType#1](../../../samples/snippets/visualbasic/VS_Snippets_CLR/EmitGenericType/VB/source.vb#1)] ## See also diff --git a/docs/fundamentals/reflection/how-to-examine-and-instantiate-generic-types-with-reflection.md b/docs/fundamentals/reflection/how-to-examine-and-instantiate-generic-types-with-reflection.md index 078e339f2ed91..b0de770af38fa 100644 --- a/docs/fundamentals/reflection/how-to-examine-and-instantiate-generic-types-with-reflection.md +++ b/docs/fundamentals/reflection/how-to-examine-and-instantiate-generic-types-with-reflection.md @@ -19,66 +19,66 @@ You can create a object that represents a constructed type by 1. Get an instance of that represents the generic type. In the following code, the type is obtained using the C# `typeof` operator (`GetType` in Visual Basic). For other ways to get a object, see . In the rest of this procedure, the type is contained in a method parameter named `t`. - [!code-csharp[HowToGeneric#2](snippets/csharp/generic-types/GenericTypes.cs#2)] + [!code-csharp[HowToGeneric#2](snippets/csharp/instantiate-generic-type/GenericTypes.cs#2)] [!code-vb[HowToGeneric#2](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#2)] -2. Use the property to determine whether the type is generic, and use the property to determine whether the type is a generic type definition. +2. Use the property to determine whether the type is generic, and use the property to determine whether the type is a generic type definition. - [!code-csharp[HowToGeneric#3](snippets/csharp/generic-types/GenericTypes.cs#3)] + [!code-csharp[HowToGeneric#3](snippets/csharp/instantiate-generic-type/GenericTypes.cs#3)] [!code-vb[HowToGeneric#3](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#3)] 3. Get an array that contains the generic type arguments, using the method. - [!code-csharp[HowToGeneric#4](snippets/csharp/generic-types/GenericTypes.cs#4)] + [!code-csharp[HowToGeneric#4](snippets/csharp/instantiate-generic-type/GenericTypes.cs#4)] [!code-vb[HowToGeneric#4](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#4)] -4. For each type argument, determine whether it is a type parameter (for example, in a generic type definition) or a type that has been specified for a type parameter (for example, in a constructed type), using the property. +4. For each type argument, determine whether it is a type parameter (for example, in a generic type definition) or a type that has been specified for a type parameter (for example, in a constructed type), using the property. - [!code-csharp[HowToGeneric#5](snippets/csharp/generic-types/GenericTypes.cs#5)] + [!code-csharp[HowToGeneric#5](snippets/csharp/instantiate-generic-type/GenericTypes.cs#5)] [!code-vb[HowToGeneric#5](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#5)] -5. In the type system, a generic type parameter is represented by an instance of , just as ordinary types are. The following code displays the name and parameter position of a object that represents a generic type parameter. The parameter position is trivial information here; it is of more interest when you're examining a type parameter that's been used as a type argument of another generic type. +5. In the type system, a generic type parameter is represented by an instance of , just as ordinary types are. The following code displays the name and parameter position of a object that represents a generic type parameter. The parameter position is trivial information here; it's of more interest when you're examining a type parameter that's been used as a type argument of another generic type. - [!code-csharp[HowToGeneric#6](snippets/csharp/generic-types/GenericTypes.cs#6)] + [!code-csharp[HowToGeneric#6](snippets/csharp/instantiate-generic-type/GenericTypes.cs#6)] [!code-vb[HowToGeneric#6](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#6)] 6. Determine the base type constraint and the interface constraints of a generic type parameter by using the method to obtain all the constraints in a single array. Constraints are not guaranteed to be in any particular order. - [!code-csharp[HowToGeneric#7](snippets/csharp/generic-types/GenericTypes.cs#7)] + [!code-csharp[HowToGeneric#7](snippets/csharp/instantiate-generic-type/GenericTypes.cs#7)] [!code-vb[HowToGeneric#7](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#7)] -7. Use the property to discover the special constraints on a type parameter, such as requiring that it be a reference type. The property also includes values that represent variance, which you can mask off as shown in the following code. +7. Use the property to discover the special constraints on a type parameter, such as requiring that it be a reference type. The property also includes values that represent variance, which you can mask off as shown in the following code. - [!code-csharp[HowToGeneric#8](snippets/csharp/generic-types/GenericTypes.cs#8)] + [!code-csharp[HowToGeneric#8](snippets/csharp/instantiate-generic-type/GenericTypes.cs#8)] [!code-vb[HowToGeneric#8](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#8)] 8. The special constraint attributes are flags, and the same flag () that represents no special constraints also represents no covariance or contravariance. Thus, to test for either of these conditions, you must use the appropriate mask. In this case, use to isolate the special constraint flags. - [!code-csharp[HowToGeneric#9](snippets/csharp/generic-types/GenericTypes.cs#9)] + [!code-csharp[HowToGeneric#9](snippets/csharp/instantiate-generic-type/GenericTypes.cs#9)] [!code-vb[HowToGeneric#9](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#9)] ## Construct an instance of a generic type -A generic type is like a template. You cannot create instances of it unless you specify real types for its generic type parameters. To do this at runtime, using reflection, requires the method. +A generic type is like a template. You can't create instances of it unless you specify real types for its generic type parameters. To do this at runtime, using reflection, requires the method. 1. Get a object that represents the generic type. The following code gets the generic type in two different ways: by using the method overload with a string describing the type, and by calling the method on the constructed type `Dictionary\` (`Dictionary(Of String, Example)` in Visual Basic). The method requires a generic type definition. - [!code-csharp[HowToGeneric#10](snippets/csharp/generic-types/GenericTypes.cs#10)] + [!code-csharp[HowToGeneric#10](snippets/csharp/instantiate-generic-type/GenericTypes.cs#10)] [!code-vb[HowToGeneric#10](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#10)] 2. Construct an array of type arguments to substitute for the type parameters. The array must contain the correct number of objects, in the same order as they appear in the type parameter list. In this case, the key (first type parameter) is of type , and the values in the dictionary are instances of a class named `Example`. - [!code-csharp[HowToGeneric#11](snippets/csharp/generic-types/GenericTypes.cs#11)] + [!code-csharp[HowToGeneric#11](snippets/csharp/instantiate-generic-type/GenericTypes.cs#11)] [!code-vb[HowToGeneric#11](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#11)] 3. Call the method to bind the type arguments to the type parameters and construct the type. - [!code-csharp[HowToGeneric#12](snippets/csharp/generic-types/GenericTypes.cs#12)] + [!code-csharp[HowToGeneric#12](snippets/csharp/instantiate-generic-type/GenericTypes.cs#12)] [!code-vb[HowToGeneric#12](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#12)] 4. Use the method overload to create an object of the constructed type. The following code stores two instances of the `Example` class in the resulting `Dictionary` object. - [!code-csharp[HowToGeneric#13](snippets/csharp/generic-types/GenericTypes.cs#13)] + [!code-csharp[HowToGeneric#13](snippets/csharp/instantiate-generic-type/GenericTypes.cs#13)] [!code-vb[HowToGeneric#13](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#13)] ## Example @@ -91,7 +91,7 @@ The code example defines a set of test types, including a generic type that illu The example constructs a type from the class by creating an array of type arguments and calling the method. The program compares the object constructed using with a object obtained using `typeof` (`GetType` in Visual Basic), demonstrating that they are the same. Similarly, the program uses the method to obtain the generic type definition of the constructed type, and compares it to the object representing the class. -[!code-csharp[HowToGeneric#1](snippets/csharp/generic-types/GenericTypes.cs#1)] +[!code-csharp[HowToGeneric#1](snippets/csharp/instantiate-generic-type/GenericTypes.cs#1)] [!code-vb[HowToGeneric#1](../../../samples/snippets/visualbasic/VS_Snippets_CLR/HowToGeneric/VB/ur.vb#1)] ## See also diff --git a/docs/fundamentals/reflection/how-to-hook-up-a-delegate-using-reflection.md b/docs/fundamentals/reflection/how-to-hook-up-a-delegate-using-reflection.md index deb6a4c4e55e5..daada6a515f58 100644 --- a/docs/fundamentals/reflection/how-to-hook-up-a-delegate-using-reflection.md +++ b/docs/fundamentals/reflection/how-to-hook-up-a-delegate-using-reflection.md @@ -92,4 +92,4 @@ The following code example shows how to hook up an existing method to an event u - - - [How to: Define and Execute Dynamic Methods](how-to-define-and-execute-dynamic-methods.md) -- [Reflection](reflection.md) +- [Reflection](overview.md) diff --git a/docs/fundamentals/reflection/reflection.md b/docs/fundamentals/reflection/overview.md similarity index 99% rename from docs/fundamentals/reflection/reflection.md rename to docs/fundamentals/reflection/overview.md index a0c728aac884f..c322238fd45d1 100644 --- a/docs/fundamentals/reflection/reflection.md +++ b/docs/fundamentals/reflection/overview.md @@ -22,7 +22,6 @@ helpviewer_keywords: - "reflection" - "discovering type information at runtime" - "type system, reflection" -ms.assetid: d1a58e7f-fb39-4d50-bf84-e3b8f9bf9775 --- # Reflection in .NET diff --git a/docs/fundamentals/reflection/snippets/csharp/construct-generic-method/Project.csproj b/docs/fundamentals/reflection/snippets/csharp/construct-generic-method/Project.csproj new file mode 100644 index 0000000000000..eec32deb298c0 --- /dev/null +++ b/docs/fundamentals/reflection/snippets/csharp/construct-generic-method/Project.csproj @@ -0,0 +1,8 @@ + + + + Exe + net481 + + + diff --git a/samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs b/docs/fundamentals/reflection/snippets/csharp/construct-generic-method/source.cs similarity index 100% rename from samples/snippets/csharp/VS_Snippets_CLR/GenericMethodHowTo/CS/source.cs rename to docs/fundamentals/reflection/snippets/csharp/construct-generic-method/source.cs diff --git a/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project.csproj b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project.csproj new file mode 100644 index 0000000000000..eec32deb298c0 --- /dev/null +++ b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project.csproj @@ -0,0 +1,8 @@ + + + + Exe + net481 + + + diff --git a/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project/DesignTimeBuild/.dtbcache.v2 b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project/DesignTimeBuild/.dtbcache.v2 new file mode 100644 index 0000000000000..339e17fa1b008 Binary files /dev/null and b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project/DesignTimeBuild/.dtbcache.v2 differ diff --git a/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project/FileContentIndex/e4c98745-d160-494e-8ebf-6c839459432b.vsidx b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project/FileContentIndex/e4c98745-d160-494e-8ebf-6c839459432b.vsidx new file mode 100644 index 0000000000000..6bd808c0136cf Binary files /dev/null and b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/Project/FileContentIndex/e4c98745-d160-494e-8ebf-6c839459432b.vsidx differ diff --git a/samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/source.cs similarity index 86% rename from samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs rename to docs/fundamentals/reflection/snippets/csharp/emit-generic-type/source.cs index f307c99bc977b..2358c5ab088c6 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/EmitGenericType/CS/source.cs +++ b/docs/fundamentals/reflection/snippets/csharp/emit-generic-type/source.cs @@ -1,4 +1,4 @@ -// +// using System; using System.Reflection; using System.Reflection.Emit; @@ -7,23 +7,23 @@ // Define a trivial base class and two trivial interfaces // to use when demonstrating constraints. // -public class ExampleBase {} +public class ExampleBase { } -public interface IExampleA {} +public interface IExampleA { } -public interface IExampleB {} +public interface IExampleB { } // Define a trivial type that can substitute for type parameter // TSecond. // -public class ExampleDerived : ExampleBase, IExampleA, IExampleB {} +public class ExampleDerived : ExampleBase, IExampleA, IExampleB { } public class Example { public static void Main() { // Define a dynamic assembly to contain the sample type. The - // assembly will not be run, but only saved to disk, so + // assembly won't be run, only saved to disk, so // AssemblyBuilderAccess.Save is specified. // // @@ -40,8 +40,9 @@ public static void Main() // // ModuleBuilder myModule = - myAssembly.DefineDynamicModule(myAsmName.Name, - myAsmName.Name + ".dll"); + myAssembly.DefineDynamicModule( + myAsmName.Name, + $"{myAsmName.Name}.dll"); // // Get type objects for the base class trivial interfaces to @@ -51,7 +52,7 @@ public static void Main() Type interfaceA = typeof(IExampleA); Type interfaceB = typeof(IExampleB); - // Define the sample type. + // Define the "Sample" type. // // TypeBuilder myType = @@ -68,7 +69,7 @@ public static void Main() // in a variable with the same name as the type parameter. // // - string[] typeParamNames = {"TFirst", "TSecond"}; + string[] typeParamNames = { "TFirst", "TSecond" }; GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames); @@ -96,21 +97,19 @@ public static void Main() // containing the interface types. // TSecond.SetBaseTypeConstraint(baseType); - Type[] interfaceTypes = {interfaceA, interfaceB}; + Type[] interfaceTypes = { interfaceA, interfaceB }; TSecond.SetInterfaceConstraints(interfaceTypes); // - // The following code adds a private field named ExampleField, - // of type TFirst. + // The following code adds a private field + // named ExampleField of type TFirst. // - FieldBuilder exField = - myType.DefineField("ExampleField", TFirst, - FieldAttributes.Private); + _ = myType.DefineField("ExampleField", TFirst, FieldAttributes.Private); // // Define a static method that takes an array of TFirst and // returns a List containing all the elements of - // the array. To define this method it is necessary to create + // the array. To define this method, it's necessary to create // the type List by calling MakeGenericType on the // generic type definition, List. (The T is omitted with // the typeof operator when you get the generic type @@ -120,7 +119,7 @@ public static void Main() // Type listOf = typeof(List<>); Type listOfTFirst = listOf.MakeGenericType(TFirst); - Type[] mParamTypes = {TFirst.MakeArrayType()}; + Type[] mParamTypes = { TFirst.MakeArrayType() }; MethodBuilder exMethod = myType.DefineMethod("ExampleMethod", @@ -138,9 +137,9 @@ public static void Main() // hard work is getting the constructor. // // The GetConstructor method is not supported on a - // GenericTypeParameterBuilder, so it is not possible to get + // GenericTypeParameterBuilder, so it's not possible to get // the constructor of List directly. There are two - // steps, first getting the constructor of List and then + // steps: getting the constructor of List, and then // calling a method that converts it to the corresponding // constructor of List. // @@ -158,7 +157,7 @@ public static void Main() // of List. The constructor argument list must be passed // as an array, with just one argument in this case. // - // Now it is possible to get the constructor of List, + // Now it's possible to get the constructor of List, // using GetConstructor on the generic type definition. To get // the constructor of List, pass List and // the constructor from List to the static @@ -170,7 +169,7 @@ public static void Main() Type ienumOf = typeof(IEnumerable<>); Type TfromListOf = listOf.GetGenericArguments()[0]; Type ienumOfT = ienumOf.MakeGenericType(TfromListOf); - Type[] ctorArgs = {ienumOfT}; + Type[] ctorArgs = { ienumOfT }; ConstructorInfo ctorPrep = listOf.GetConstructor(ctorArgs); ConstructorInfo ctor = @@ -184,7 +183,7 @@ public static void Main() // Create the type and save the assembly. // Type finished = myType.CreateType(); - myAssembly.Save(myAsmName.Name+".dll"); + myAssembly.Save(myAsmName.Name + ".dll"); // // Invoke the method. @@ -199,7 +198,7 @@ public static void Main() // constructed type. // // - Type[] typeArgs = {typeof(Example), typeof(ExampleDerived)}; + Type[] typeArgs = { typeof(Example), typeof(ExampleDerived) }; Type constructed = finished.MakeGenericType(typeArgs); MethodInfo mi = constructed.GetMethod("ExampleMethod"); // @@ -211,11 +210,11 @@ public static void Main() // on the resulting List. // // - Example[] input = {new Example(), new Example()}; - object[] arguments = {input}; + Example[] input = { new Example(), new Example() }; + object[] arguments = { input }; List listX = - (List) mi.Invoke(null, arguments); + (List)mi.Invoke(null, arguments); Console.WriteLine($"\nThere are {listX.Count} elements in the List."); // @@ -238,14 +237,11 @@ private static void DisplayGenericParameters(Type t) Type[] typeParameters = t.GetGenericArguments(); Console.WriteLine($"\nListing {typeParameters.Length} type parameters for type '{t}'."); - foreach( Type tParam in typeParameters ) + foreach (Type tParam in typeParameters) { - Console.WriteLine($""" - - Type parameter {tParam.ToString()}: - """); + Console.WriteLine($"\nType parameter {tParam}:"); - foreach( Type c in tParam.GetGenericParameterConstraints() ) + foreach (Type c in tParam.GetGenericParameterConstraints()) { if (c.IsInterface) { @@ -284,7 +280,7 @@ private static void ListConstraintAttributes(Type t) } if ((constraints & GenericParameterAttributes.DefaultConstructorConstraint) - !=GenericParameterAttributes.None) + != GenericParameterAttributes.None) { Console.WriteLine(" DefaultConstructorConstraint"); } diff --git a/docs/fundamentals/reflection/snippets/csharp/generic-types/GenericTypes.cs b/docs/fundamentals/reflection/snippets/csharp/instantiate-generic-type/GenericTypes.cs similarity index 100% rename from docs/fundamentals/reflection/snippets/csharp/generic-types/GenericTypes.cs rename to docs/fundamentals/reflection/snippets/csharp/instantiate-generic-type/GenericTypes.cs diff --git a/docs/fundamentals/reflection/snippets/csharp/generic-types/Project.csproj b/docs/fundamentals/reflection/snippets/csharp/instantiate-generic-type/Project.csproj similarity index 100% rename from docs/fundamentals/reflection/snippets/csharp/generic-types/Project.csproj rename to docs/fundamentals/reflection/snippets/csharp/instantiate-generic-type/Project.csproj diff --git a/docs/fundamentals/runtime-libraries/snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/CreateAndRunAssembly.cs b/docs/fundamentals/runtime-libraries/snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/CreateAndRunAssembly.cs index f4a5c776d758c..29f6e80cad3e1 100644 --- a/docs/fundamentals/runtime-libraries/snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/CreateAndRunAssembly.cs +++ b/docs/fundamentals/runtime-libraries/snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/CreateAndRunAssembly.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Reflection; using System.Reflection.Emit; @@ -15,11 +15,15 @@ public static void Main() // public static void CreateSaveAndRunAssembly() { - PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), typeof(object).Assembly); + PersistedAssemblyBuilder ab = new(new AssemblyName("MyAssembly"), typeof(object).Assembly); ModuleBuilder mob = ab.DefineDynamicModule("MyModule"); - TypeBuilder tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); - MethodBuilder meb = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static, - typeof(int), new Type[] { typeof(int), typeof(int) }); + TypeBuilder tb = mob.DefineType( + "MyType", + TypeAttributes.Public | TypeAttributes.Class); + MethodBuilder meb = tb.DefineMethod( + "SumMethod", + MethodAttributes.Public | MethodAttributes.Static, + typeof(int), [typeof(int), typeof(int)]); ILGenerator il = meb.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); @@ -29,20 +33,21 @@ public static void CreateSaveAndRunAssembly() tb.CreateType(); using var stream = new MemoryStream(); - ab.Save(stream); // or pass filename to save into a file + ab.Save(stream); // Or pass filename to save into a file. stream.Seek(0, SeekOrigin.Begin); Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(stream); MethodInfo method = assembly.GetType("MyType").GetMethod("SumMethod"); - Console.WriteLine(method.Invoke(null, new object[] { 5, 10 })); + Console.WriteLine(method.Invoke(null, [5, 10])); } // + // public static void CreatePersistedAssemblyBuilderCoreAssemblyWithMetadataLoadContext(string refAssembliesPath) { - PathAssemblyResolver resolver = new PathAssemblyResolver(Directory.GetFiles(refAssembliesPath, "*.dll")); - using MetadataLoadContext context = new MetadataLoadContext(resolver); + PathAssemblyResolver resolver = new(Directory.GetFiles(refAssembliesPath, "*.dll")); + using MetadataLoadContext context = new(resolver); Assembly coreAssembly = context.CoreAssembly; - PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyDynamicAssembly"), coreAssembly); + PersistedAssemblyBuilder ab = new(new AssemblyName("MyDynamicAssembly"), coreAssembly); TypeBuilder typeBuilder = ab.DefineDynamicModule("MyModule").DefineType("Test", TypeAttributes.Public); MethodBuilder methodBuilder = typeBuilder.DefineMethod("Method", MethodAttributes.Public, coreAssembly.GetType(typeof(int).FullName), Type.EmptyTypes); // .. add members and save the assembly diff --git a/docs/fundamentals/runtime-libraries/system-net-http-httpclient.md b/docs/fundamentals/runtime-libraries/system-net-http-httpclient.md index cf20a5f515fe0..2899bb71e86f7 100644 --- a/docs/fundamentals/runtime-libraries/system-net-http-httpclient.md +++ b/docs/fundamentals/runtime-libraries/system-net-http-httpclient.md @@ -11,11 +11,11 @@ The class instance acts as a session to send H ## Instancing - is intended to be instantiated once and reused throughout the life of an application. In .NET Core and .NET 5+, HttpClient pools connections inside the handler instance and reuses a connection across multiple requests. If you instantiate an HttpClient class for every request, the number of sockets available under heavy loads will be exhausted. This exhaustion will result in errors. + is intended to be instantiated once and reused throughout the life of an application. In .NET Core and .NET 5+, `HttpClient` pools connections inside the handler instance and reuses a connection across multiple requests. If you instantiate an `HttpClient` class for every request, the number of sockets available under heavy loads will be exhausted. This exhaustion will result in errors. -You can configure additional options by passing in a "handler", such as (or in .NET Core 2.1 or later), as part of the constructor. The connection properties on the handler cannot be changed once a request has been submitted, so one reason to create a new HttpClient instance would be if you need to change the connection properties. If different requests require different settings, this may also lead to an application having multiple instances, where each instance is configured appropriately, and then requests are issued on the relevant client. +You can configure additional options by passing in a "handler", such as (or in .NET Core 2.1 or later), as part of the constructor. The connection properties on the handler cannot be changed once a request has been submitted, so one reason to create a new `HttpClient` instance would be if you need to change the connection properties. If different requests require different settings, this may also lead to an application having multiple instances, where each instance is configured appropriately, and then requests are issued on the relevant client. -HttpClient only resolves DNS entries when a connection is created. It does not track any time to live (TTL) durations specified by the DNS server. If DNS entries change regularly, which can happen in some container scenarios, the client won't respect those updates. To solve this issue, you can limit the lifetime of the connection by setting the property, so that DNS lookup is required when the connection is replaced. +`HttpClient` only resolves DNS entries when a connection is created. It does not track any time to live (TTL) durations specified by the DNS server. If DNS entries change regularly, which can happen in some container scenarios, the client won't respect those updates. To solve this issue, you can limit the lifetime of the connection by setting the property, so that DNS lookup is required when the connection is replaced. ```csharp public class GoodController : ApiController @@ -34,11 +34,11 @@ public class GoodController : ApiController } ``` -As an alternative to creating only one HttpClient instance, you can also use to manage the HttpClient instances for you. For more information, see [Guidelines for using HttpClient](/dotnet/fundamentals/networking/httpclient-guidelines). +As an alternative to creating only one `HttpClient` instance, you can also use to manage the `HttpClient` instances for you. For more information, see [Guidelines for using HttpClient](/dotnet/fundamentals/networking/httpclient-guidelines). ## Derivation -The also acts as a base class for more specific HTTP clients. An example would be a FacebookHttpClient that provides additional methods specific to a Facebook web service (for example, a `GetFriends` method). Derived classes should not override the virtual methods on the class. Instead, use a constructor overload that accepts to configure any pre-request or post-request processing. +The also acts as a base class for more specific HTTP clients. An example would be a `FacebookHttpClient` that provides additional methods specific to a Facebook web service (for example, a `GetFriends` method). Derived classes should not override the virtual methods on the class. Instead, use a constructor overload that accepts to configure any pre-request or post-request processing. ## Transports @@ -80,18 +80,18 @@ Certain aspects of 's behavior are customizable ## Connection pooling -HttpClient pools HTTP connections where possible and uses them for more than one request. This can have a significant performance benefit, especially for HTTPS requests, as the connection handshake is only done once. +`HttpClient` pools HTTP connections where possible and uses them for more than one request. This can have a significant performance benefit, especially for HTTPS requests, as the connection handshake is only done once. Connection pool properties can be configured on a or passed in during construction, including , , and . -Disposing of the HttpClient instance closes the open connections and cancels any pending requests. +Disposing of the `HttpClient` instance closes the open connections and cancels any pending requests. > [!NOTE] > If you concurrently send HTTP/1.1 requests to the same server, new connections can be created. Even if you reuse the `HttpClient` instance, if the rate of requests is high, or if there are any firewall limitations, that can exhaust the available sockets because of default TCP cleanup timers. To limit the number of concurrent connections, you can set the `MaxConnectionsPerServer` property. By default, the number of concurrent HTTP/1.1 connections is unlimited. ## Buffering and request lifetime -By default, HttpClient methods (except ) buffer the responses from the server, reading all the response body into memory before returning the async result. Those requests will continue until one of the following occurs: +By default, `HttpClient` methods (except ) buffer the responses from the server, reading all the response body into memory before returning the async result. Those requests will continue until one of the following occurs: - The succeeds and returns a result. - The is reached, in which case the will be cancelled. @@ -119,20 +119,20 @@ The following methods are thread safe: ## Proxies -By default, HttpClient reads proxy configuration from environment variables or user/system settings, depending on the platform. You can change this behavior by passing a or to, in order of precedence: +By default, `HttpClient` reads proxy configuration from environment variables or user/system settings, depending on the platform. You can change this behavior by passing a or to, in order of precedence: -- The property on a HttpClientHandler passed in during HttpClient construction +- The property on an `HttpClientHandler` passed in during `HttpClient` construction - The static property (affects all instances) You can disable the proxy using . The default configuration for Windows users is to try and detect a proxy using network discovery, which can be slow. For high throughput applications where it's known that a proxy isn't required, you should disable the proxy. -Proxy settings (like ) should be changed only before the first request is made using the HttpClient. Changes made after using the HttpClient for the first time may not be reflected in subsequent requests. +Proxy settings (like ) should be changed only before the first request is made using the `HttpClient`. Changes made after using the `HttpClient` for the first time may not be reflected in subsequent requests. ## Timeouts -You can use to set a default timeout for all HTTP requests from the HttpClient instance. The timeout only applies to the xxxAsync methods that cause a request/response to be initiated. If the timeout is reached, the for that request is cancelled. +You can use to set a default timeout for all HTTP requests from the `HttpClient` instance. The timeout only applies to the xxxAsync methods that cause a request/response to be initiated. If the timeout is reached, the for that request is cancelled. -You can set some additional timeouts if you pass in a instance when constructing the HttpClient object: +You can set some additional timeouts if you pass in a instance when constructing the `HttpClient` object: | Property | Description | | ------------ | -------------- | @@ -141,4 +141,4 @@ You can set some additional timeouts if you pass in a | If a connection in the connection pool is idle for this long, the connection is closed. | | | If request has an "Expect: 100-continue" header, it delays sending content until the timeout or until a "100-continue" response is received. | -HttpClient only resolves DNS entries when the connections are created. It does not track any time to live (TTL) durations specified by the DNS server. If DNS entries are changing regularly, which can happen in some container scenarios, you can use the to limit the lifetime of the connection so that DNS lookup is required when replacing the connection. +`HttpClient` only resolves DNS entries when the connections are created. It does not track any time to live (TTL) durations specified by the DNS server. If DNS entries are changing regularly, which can happen in some container scenarios, you can use the to limit the lifetime of the connection so that DNS lookup is required when replacing the connection. diff --git a/docs/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md b/docs/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md index 2c2a4fb57a63a..4d995e4757b63 100644 --- a/docs/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md +++ b/docs/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md @@ -7,12 +7,12 @@ ms.date: 05/10/2024 [!INCLUDE [context](includes/context.md)] -The API wasn't originally ported to .NET (Core) because the implementation depended heavily on Windows-specific native code that also wasn't ported. New in .NET 9, the class adds a fully managed `Reflection.Emit` implementation that supports saving. This implementation has no dependency on the pre-existing, runtime-specific `Reflection.Emit` implementation. That is, now there are two different implementations in .NET, runnable and persisted. To run the persisted assembly, first save it into a memory stream or a file, then load it back. +The API wasn't originally ported to .NET (Core) because the implementation depended heavily on Windows-specific native code that also wasn't ported. .NET 9 added the class, which provides a fully managed `Reflection.Emit` implementation that supports saving. This implementation has no dependency on the pre-existing, runtime-specific `Reflection.Emit` implementation. That is, now there are two different implementations in .NET: *runnable* and *persisted*. To run the persisted assembly, first save it into a memory stream or a file, then load it back. Before `PersistedAssemblyBuilder`, you could only run a generated assembly and not save it. Since the assembly was in-memory only, it was difficult to debug. Advantages of saving a dynamic assembly to a file are: - You can verify the generated assembly with tools such as ILVerify, or decompile and manually examine it with tools such as ILSpy. -- The saved assembly can be loaded directly, no need to compile again, which can decrease application startup time. +- The saved assembly can be loaded directly, without needing to compile again, which can decrease application startup time. To create a `PersistedAssemblyBuilder` instance, use the constructor. The `coreAssembly` parameter is used to resolve base runtime types and can be used for resolving reference assembly versioning: diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index 9d9d6332a0bbe..0114c6ac17aba 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1497,7 +1497,7 @@ items: - name: Reflection items: - name: Overview - href: reflection/reflection.md + href: reflection/overview.md - name: View type information href: reflection/viewing-type-information.md - name: Reflection and generic types diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj index 51aeefc5d5848..f2796fe2a6757 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/Client/Client.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj index 6079d52418fe9..3b1a1d6e7db39 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/GrainInterfaces/GrainInterfaces.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj index 81c0b0d22043b..a5aec34961463 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/Grains/Grains.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj b/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj index 176a1b5460f00..b5e99e79e51b2 100644 --- a/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj +++ b/docs/orleans/tutorials-and-samples/snippets/minimal/Silo/Silo.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/docs/standard/assembly/inspect-contents-using-metadataloadcontext.md b/docs/standard/assembly/inspect-contents-using-metadataloadcontext.md index 29d82d255065c..97e8733c290d1 100644 --- a/docs/standard/assembly/inspect-contents-using-metadataloadcontext.md +++ b/docs/standard/assembly/inspect-contents-using-metadataloadcontext.md @@ -43,4 +43,4 @@ For a complete code example, see the [Inspect assembly contents using MetadataLo ## See also -- [Reflection in .NET](../../fundamentals/reflection/reflection.md) +- [Reflection in .NET](../../fundamentals/reflection/overview.md) diff --git a/docs/standard/garbage-collection/implementing-disposeasync.md b/docs/standard/garbage-collection/implementing-disposeasync.md index c309de1f2b1e2..3af8e8524b161 100644 --- a/docs/standard/garbage-collection/implementing-disposeasync.md +++ b/docs/standard/garbage-collection/implementing-disposeasync.md @@ -44,11 +44,17 @@ public async ValueTask DisposeAsync() // Perform async cleanup. await DisposeAsyncCore().ConfigureAwait(false); + // Dispose of unmanaged resources. + Dispose(false); + // Suppress finalization. GC.SuppressFinalize(this); } ``` +> [!NOTE] +> One primary difference in the async dispose pattern compared to the dispose pattern, is that the call from to the `Dispose(bool)` overload method is given `false` as an argument. When implementing the method, however, `true` is passed instead. This helps ensure functional equivalence with the synchronous dispose pattern, and further ensures that finalizer code paths still get invoked. In other words, the `DisposeAsyncCore()` method will dispose of managed resources asynchronously, so you don't want to dispose of them synchronously as well. Therefore, call `Dispose(false)` instead of `Dispose(true)`. + ### The `DisposeAsyncCore` method The `DisposeAsyncCore()` method is intended to perform the asynchronous cleanup of managed resources or for cascading calls to `DisposeAsync()`. It encapsulates the common asynchronous cleanup operations when a subclass inherits a base class that is an implementation of . The `DisposeAsyncCore()` method is `virtual` so that derived classes can define custom cleanup in their overrides. diff --git a/docs/standard/garbage-collection/snippets/dispose-async/ExampleConjunctiveDisposable.cs b/docs/standard/garbage-collection/snippets/dispose-async/ExampleConjunctiveDisposable.cs index 2a7966849a697..0dfbe02bf1966 100644 --- a/docs/standard/garbage-collection/snippets/dispose-async/ExampleConjunctiveDisposable.cs +++ b/docs/standard/garbage-collection/snippets/dispose-async/ExampleConjunctiveDisposable.cs @@ -13,6 +13,7 @@ public async ValueTask DisposeAsync() { await DisposeAsyncCore().ConfigureAwait(false); + Dispose(disposing: false); GC.SuppressFinalize(this); } diff --git a/docs/visual-basic/language-reference/error-messages/type-of-member-membername-is-not-cls-compliant.md b/docs/visual-basic/language-reference/error-messages/type-of-member-membername-is-not-cls-compliant.md index 61e1845d0d705..bb12323c65d3a 100644 --- a/docs/visual-basic/language-reference/error-messages/type-of-member-membername-is-not-cls-compliant.md +++ b/docs/visual-basic/language-reference/error-messages/type-of-member-membername-is-not-cls-compliant.md @@ -39,4 +39,4 @@ The data type specified for this member is not part of the [Language Independenc ## See also -- [Reflection](../../../fundamentals/reflection/reflection.md) +- [Reflection](../../../fundamentals/reflection/overview.md) diff --git a/docs/visual-basic/language-reference/error-messages/underlying-type-typename-of-enum-is-not-cls-compliant.md b/docs/visual-basic/language-reference/error-messages/underlying-type-typename-of-enum-is-not-cls-compliant.md index 7d7cd9a793930..14087af5350c6 100644 --- a/docs/visual-basic/language-reference/error-messages/underlying-type-typename-of-enum-is-not-cls-compliant.md +++ b/docs/visual-basic/language-reference/error-messages/underlying-type-typename-of-enum-is-not-cls-compliant.md @@ -40,4 +40,4 @@ The data type specified for this enumeration is not part of the [Language Indepe ## See also - [Reflection (Visual Basic)](../../programming-guide/concepts/reflection.md) -- [Reflection](../../../fundamentals/reflection/reflection.md) +- [Reflection](../../../fundamentals/reflection/overview.md) diff --git a/docs/visual-basic/language-reference/statements/property-statement.md b/docs/visual-basic/language-reference/statements/property-statement.md index afdfe6267a6f4..9c850d25be80c 100644 --- a/docs/visual-basic/language-reference/statements/property-statement.md +++ b/docs/visual-basic/language-reference/statements/property-statement.md @@ -209,7 +209,7 @@ The following example declares a property in a class. The following example shows how to create a parameterized property, also called an indexer, which allows array-like access to a collection: -[!code-vb[VbVbalrStatements#52](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrStatements/VB/Class1.vb#52)] +[!code-vb[VbVbalrStatements#59](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrStatements/VB/Class1.vb#59)] For comprehensive examples of property usage, including automatic implementation, mixed access levels, and validation scenarios, see [Property Procedures](../../programming-guide/language-features/procedures/property-procedures.md). diff --git a/docs/visual-basic/programming-guide/concepts/reflection.md b/docs/visual-basic/programming-guide/concepts/reflection.md index e5300f0d152d5..722fdf07d9a08 100644 --- a/docs/visual-basic/programming-guide/concepts/reflection.md +++ b/docs/visual-basic/programming-guide/concepts/reflection.md @@ -6,59 +6,59 @@ ms.assetid: d991bc0f-d16a-4ac5-9351-70e5c5b9891b --- # Reflection (Visual Basic) -Reflection provides objects (of type ) that describe assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them. For more information, see [Attributes](../../../standard/attributes/index.md). - - Here's a simple example of reflection using the static method `GetType` - inherited by all types from the `Object` base class - to obtain the type of a variable: - -```vb -' Using GetType to obtain type information: -Dim i As Integer = 42 -Dim type As System.Type = i.GetType() -System.Console.WriteLine(type) -``` - - The output is: - - `System.Int32` - - The following example uses reflection to obtain the full name of the loaded assembly. - -```vb -' Using Reflection to get information from an Assembly: -Dim info As System.Reflection.Assembly = GetType(System.Int32).Assembly -System.Console.WriteLine(info) -``` - - The output is: - - `mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089` - -## Reflection Overview - - Reflection is useful in the following situations: - -- When you have to access attributes in your program's metadata. For more information, see [Retrieving Information Stored in Attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md). - -- For examining and instantiating types in an assembly. - -- For building new types at run time. Use classes in . - -- For performing late binding, accessing methods on types created at run time. See the topic [Dynamically Loading and Using Types](../../../fundamentals/reflection/dynamically-loading-and-using-types.md). - -## Related Sections - - For more information: - -- [Reflection](../../../fundamentals/reflection/reflection.md) - -- [Viewing Type Information](../../../fundamentals/reflection/viewing-type-information.md) - -- [Reflection and Generic Types](../../../fundamentals/reflection/reflection-and-generic-types.md) - -- - -- [Retrieving Information Stored in Attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md) - +Reflection provides objects (of type ) that describe assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them. For more information, see [Attributes](../../../standard/attributes/index.md). + + Here's a simple example of reflection using the static method `GetType` - inherited by all types from the `Object` base class - to obtain the type of a variable: + +```vb +' Using GetType to obtain type information: +Dim i As Integer = 42 +Dim type As System.Type = i.GetType() +System.Console.WriteLine(type) +``` + + The output is: + + `System.Int32` + + The following example uses reflection to obtain the full name of the loaded assembly. + +```vb +' Using Reflection to get information from an Assembly: +Dim info As System.Reflection.Assembly = GetType(System.Int32).Assembly +System.Console.WriteLine(info) +``` + + The output is: + + `mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089` + +## Reflection Overview + + Reflection is useful in the following situations: + +- When you have to access attributes in your program's metadata. For more information, see [Retrieving Information Stored in Attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md). + +- For examining and instantiating types in an assembly. + +- For building new types at run time. Use classes in . + +- For performing late binding, accessing methods on types created at run time. See the topic [Dynamically Loading and Using Types](../../../fundamentals/reflection/dynamically-loading-and-using-types.md). + +## Related Sections + + For more information: + +- [Reflection](../../../fundamentals/reflection/overview.md) + +- [Viewing Type Information](../../../fundamentals/reflection/viewing-type-information.md) + +- [Reflection and Generic Types](../../../fundamentals/reflection/reflection-and-generic-types.md) + +- + +- [Retrieving Information Stored in Attributes](../../../standard/attributes/retrieving-information-stored-in-attributes.md) + ## See also - [Visual Basic Programming Guide](../index.md) diff --git a/samples/snippets/fsharp/lang-ref-1/snippet1001.fs b/samples/snippets/fsharp/lang-ref-1/snippet1001.fs index ec3ca25918762..6452960196fc6 100644 --- a/samples/snippets/fsharp/lang-ref-1/snippet1001.fs +++ b/samples/snippets/fsharp/lang-ref-1/snippet1001.fs @@ -1,7 +1,7 @@ let str1 = "abc -def" + def" let str2 = "abc\ -def" + def" diff --git a/samples/snippets/standard/data/sqlite/AggregateFunctionSample/AggregateFunctionSample.csproj b/samples/snippets/standard/data/sqlite/AggregateFunctionSample/AggregateFunctionSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/AggregateFunctionSample/AggregateFunctionSample.csproj +++ b/samples/snippets/standard/data/sqlite/AggregateFunctionSample/AggregateFunctionSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/AsyncSample/AsyncSample.csproj b/samples/snippets/standard/data/sqlite/AsyncSample/AsyncSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/AsyncSample/AsyncSample.csproj +++ b/samples/snippets/standard/data/sqlite/AsyncSample/AsyncSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/BackupSample/BackupSample.csproj b/samples/snippets/standard/data/sqlite/BackupSample/BackupSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/BackupSample/BackupSample.csproj +++ b/samples/snippets/standard/data/sqlite/BackupSample/BackupSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/BatchingSample/BatchingSample.csproj b/samples/snippets/standard/data/sqlite/BatchingSample/BatchingSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/BatchingSample/BatchingSample.csproj +++ b/samples/snippets/standard/data/sqlite/BatchingSample/BatchingSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/BulkInsertSample/BulkInsertSample.csproj b/samples/snippets/standard/data/sqlite/BulkInsertSample/BulkInsertSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/BulkInsertSample/BulkInsertSample.csproj +++ b/samples/snippets/standard/data/sqlite/BulkInsertSample/BulkInsertSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/CollationSample/CollationSample.csproj b/samples/snippets/standard/data/sqlite/CollationSample/CollationSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/CollationSample/CollationSample.csproj +++ b/samples/snippets/standard/data/sqlite/CollationSample/CollationSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/DapperSample/DapperSample.csproj b/samples/snippets/standard/data/sqlite/DapperSample/DapperSample.csproj index 574921cd66b9c..c16561fdcfe86 100644 --- a/samples/snippets/standard/data/sqlite/DapperSample/DapperSample.csproj +++ b/samples/snippets/standard/data/sqlite/DapperSample/DapperSample.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/DateAndTimeSample/DateAndTimeSample.csproj b/samples/snippets/standard/data/sqlite/DateAndTimeSample/DateAndTimeSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/DateAndTimeSample/DateAndTimeSample.csproj +++ b/samples/snippets/standard/data/sqlite/DateAndTimeSample/DateAndTimeSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/DeferredTransactionSample/DeferredTransactionSample.csproj b/samples/snippets/standard/data/sqlite/DeferredTransactionSample/DeferredTransactionSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/DeferredTransactionSample/DeferredTransactionSample.csproj +++ b/samples/snippets/standard/data/sqlite/DeferredTransactionSample/DeferredTransactionSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/DirtyReadSample/DirtyReadSample.csproj b/samples/snippets/standard/data/sqlite/DirtyReadSample/DirtyReadSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/DirtyReadSample/DirtyReadSample.csproj +++ b/samples/snippets/standard/data/sqlite/DirtyReadSample/DirtyReadSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/EncryptionSample/EncryptionSample.csproj b/samples/snippets/standard/data/sqlite/EncryptionSample/EncryptionSample.csproj index 82a061c4d71a4..2c91afdea3f60 100644 --- a/samples/snippets/standard/data/sqlite/EncryptionSample/EncryptionSample.csproj +++ b/samples/snippets/standard/data/sqlite/EncryptionSample/EncryptionSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/ExtensionsSample/ExtensionsSample.csproj b/samples/snippets/standard/data/sqlite/ExtensionsSample/ExtensionsSample.csproj index 533a0653271b2..a322b492ed341 100644 --- a/samples/snippets/standard/data/sqlite/ExtensionsSample/ExtensionsSample.csproj +++ b/samples/snippets/standard/data/sqlite/ExtensionsSample/ExtensionsSample.csproj @@ -7,9 +7,9 @@ - + - + diff --git a/samples/snippets/standard/data/sqlite/HelloWorldSample/HelloWorldSample.csproj b/samples/snippets/standard/data/sqlite/HelloWorldSample/HelloWorldSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/HelloWorldSample/HelloWorldSample.csproj +++ b/samples/snippets/standard/data/sqlite/HelloWorldSample/HelloWorldSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/InteropSample/InteropSample.csproj b/samples/snippets/standard/data/sqlite/InteropSample/InteropSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/InteropSample/InteropSample.csproj +++ b/samples/snippets/standard/data/sqlite/InteropSample/InteropSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/RegularExpressionSample/RegularExpressionSample.csproj b/samples/snippets/standard/data/sqlite/RegularExpressionSample/RegularExpressionSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/RegularExpressionSample/RegularExpressionSample.csproj +++ b/samples/snippets/standard/data/sqlite/RegularExpressionSample/RegularExpressionSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/ResultMetadataSample/ResultMetadataSample.csproj b/samples/snippets/standard/data/sqlite/ResultMetadataSample/ResultMetadataSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/ResultMetadataSample/ResultMetadataSample.csproj +++ b/samples/snippets/standard/data/sqlite/ResultMetadataSample/ResultMetadataSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/SavepointSample/SavepointSample.csproj b/samples/snippets/standard/data/sqlite/SavepointSample/SavepointSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/SavepointSample/SavepointSample.csproj +++ b/samples/snippets/standard/data/sqlite/SavepointSample/SavepointSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/ScalarFunctionSample/ScalarFunctionSample.csproj b/samples/snippets/standard/data/sqlite/ScalarFunctionSample/ScalarFunctionSample.csproj index e413b78451b97..7c0c4456e0c36 100644 --- a/samples/snippets/standard/data/sqlite/ScalarFunctionSample/ScalarFunctionSample.csproj +++ b/samples/snippets/standard/data/sqlite/ScalarFunctionSample/ScalarFunctionSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/SqliteProviderSample/SqliteProviderSample.csproj b/samples/snippets/standard/data/sqlite/SqliteProviderSample/SqliteProviderSample.csproj index e08f8d646b538..66a863d8580b4 100644 --- a/samples/snippets/standard/data/sqlite/SqliteProviderSample/SqliteProviderSample.csproj +++ b/samples/snippets/standard/data/sqlite/SqliteProviderSample/SqliteProviderSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/StreamingSample/StreamingSample.csproj b/samples/snippets/standard/data/sqlite/StreamingSample/StreamingSample.csproj index 17566271c1363..1984ac36ae8a4 100644 --- a/samples/snippets/standard/data/sqlite/StreamingSample/StreamingSample.csproj +++ b/samples/snippets/standard/data/sqlite/StreamingSample/StreamingSample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/standard/data/sqlite/SystemLibrarySample/SystemLibrarySample.csproj b/samples/snippets/standard/data/sqlite/SystemLibrarySample/SystemLibrarySample.csproj index 9e40d1bfc6f70..13c156c075a44 100644 --- a/samples/snippets/standard/data/sqlite/SystemLibrarySample/SystemLibrarySample.csproj +++ b/samples/snippets/standard/data/sqlite/SystemLibrarySample/SystemLibrarySample.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrStatements/VB/Class1.vb b/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrStatements/VB/Class1.vb index 25a361c240d50..4d6b8f353be37 100644 --- a/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrStatements/VB/Class1.vb +++ b/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrStatements/VB/Class1.vb @@ -599,7 +599,7 @@ Public Class Class1 '******************************************************************** - ' + ' Class SampleCollection ' Define a local collection to store strings. Private items As New List(Of String) @@ -637,7 +637,7 @@ Public Class Class1 items.Add(item) End Sub End Class - ' + ' '********************************************************************