diff --git a/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj b/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj index 301eae1cf9e17..4d471bc8e1be9 100644 --- a/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj +++ b/docs/ai/quickstarts/snippets/build-chat-app/azure-openai/ChatAppAI.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/ai/quickstarts/snippets/mcp-client/MinimalMCPClient.csproj b/docs/ai/quickstarts/snippets/mcp-client/MinimalMCPClient.csproj index 65e3620145c2f..bae61d60be266 100644 --- a/docs/ai/quickstarts/snippets/mcp-client/MinimalMCPClient.csproj +++ b/docs/ai/quickstarts/snippets/mcp-client/MinimalMCPClient.csproj @@ -9,7 +9,7 @@ - + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.AddMessages/ConsoleAI.AddMessages.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.AddMessages/ConsoleAI.AddMessages.csproj index e64080331bc30..0c3e9fa73fbd2 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.AddMessages/ConsoleAI.AddMessages.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.AddMessages/ConsoleAI.AddMessages.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CacheResponses/ConsoleAI.CacheResponses.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CacheResponses/ConsoleAI.CacheResponses.csproj index 36cec419d6f10..1d362045100d2 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CacheResponses/ConsoleAI.CacheResponses.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.CacheResponses/ConsoleAI.CacheResponses.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.ProvideOptions/ConsoleAI.ProvideOptions.csproj b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.ProvideOptions/ConsoleAI.ProvideOptions.csproj index cb6bfe575f31a..0c3e9fa73fbd2 100644 --- a/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.ProvideOptions/ConsoleAI.ProvideOptions.csproj +++ b/docs/ai/snippets/microsoft-extensions-ai/ConsoleAI.ProvideOptions/ConsoleAI.ProvideOptions.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 cb6bfe575f31a..0c3e9fa73fbd2 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/azure/includes/dotnet-all.md b/docs/azure/includes/dotnet-all.md index dfed06eef2e2c..a956f5bdc11eb 100644 --- a/docs/azure/includes/dotnet-all.md +++ b/docs/azure/includes/dotnet-all.md @@ -84,8 +84,8 @@ | OpenTelemetry AspNetCore | NuGet [1.3.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.AspNetCore/1.3.0) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.AspNetCore-readme) | GitHub [1.3.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.AspNetCore_1.3.0/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/) | | OpenTelemetry Exporter | NuGet [1.4.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.4.0) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.Exporter-readme) | GitHub [1.4.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.4.0/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-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright/1.0.0-beta.1) | | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright/) | -| Playwright NUnit | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright.NUnit/1.0.0-beta.1) | | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright.NUnit_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright.NUnit/) | +| Playwright | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Developer.Playwright-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright/) | +| Playwright NUnit | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright.NUnit/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Developer.Playwright.NUnit-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright.NUnit_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright.NUnit/) | | Programmable Connectivity | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Communication.ProgrammableConnectivity/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Communication.ProgrammableConnectivity-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Communication.ProgrammableConnectivity_1.0.0-beta.1/sdk/communication/Azure.Communication.ProgrammableConnectivity/) | | Provisioning | NuGet [1.1.0](https://www.nuget.org/packages/Azure.Provisioning/1.1.0) | [docs](/dotnet/api/overview/azure/Provisioning-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Provisioning_1.1.0/sdk/provisioning/Azure.Provisioning/) | | Provisioning - Resources | NuGet [0.2.0](https://www.nuget.org/packages/Azure.Provisioning.Resources/0.2.0) | [docs](/dotnet/api/overview/azure/Provisioning.Resources-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [0.2.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Provisioning.Resources_0.2.0/sdk/provisioning/Azure.Provisioning.Resources/) | @@ -545,7 +545,7 @@ | Microsoft.Azure.Functions.Worker.Extensions.EventHubs | NuGet [6.5.0](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.EventHubs/6.5.0) | | | | Microsoft.Azure.Functions.Worker.Extensions.Http | NuGet [3.3.0](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Http/3.3.0) | | | | Microsoft.Azure.Functions.Worker.Extensions.Kafka | NuGet [4.1.2](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Kafka/4.1.2) | | | -| Microsoft.Azure.Functions.Worker.Extensions.Kusto | NuGet [1.0.12-Preview](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Kusto/1.0.12-Preview) | | | +| Microsoft.Azure.Functions.Worker.Extensions.Kusto | NuGet [1.0.13-Preview](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Kusto/1.0.13-Preview) | | | | Microsoft.Azure.Functions.Worker.Extensions.OpenApi | NuGet [1.4.0](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.OpenApi/1.4.0)
NuGet [2.0.0-preview2](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.OpenApi/2.0.0-preview2) | | | | Microsoft.Azure.Functions.Worker.Extensions.RabbitMQ | NuGet [2.1.0](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.RabbitMQ/2.1.0) | | | | Microsoft.Azure.Functions.Worker.Extensions.Rpc | NuGet [1.0.1](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Rpc/1.0.1) | | | @@ -567,7 +567,7 @@ | Microsoft.Azure.Functions.Worker.Sdk.Analyzers | NuGet [1.2.2](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Sdk.Analyzers/1.2.2) | | | | Microsoft.Azure.Functions.Worker.Sdk.Generators | NuGet [1.3.5](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Sdk.Generators/1.3.5) | | | | Microsoft.Azure.WebJobs.CosmosDb.ChangeProcessor | NuGet [1.0.4](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.CosmosDb.ChangeProcessor/1.0.4) | | | -| Microsoft.Azure.WebJobs.Extensions.Kusto | NuGet [1.0.12-Preview](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Kusto/1.0.12-Preview) | | | +| Microsoft.Azure.WebJobs.Extensions.Kusto | NuGet [1.0.13-Preview](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Kusto/1.0.13-Preview) | | | | Microsoft.Azure.WebJobs.Extensions.Rpc | NuGet [3.0.41](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Rpc/3.0.41) | | | | Microsoft.Azure.WebJobs.Rpc.Core | NuGet [3.0.41](https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Rpc.Core/3.0.41) | | | | Service Bus - Message ID plugin | NuGet [2.0.0](https://www.nuget.org/packages/Microsoft.Azure.ServiceBus.MessageIdPlugin/2.0.0) | | | diff --git a/docs/azure/includes/dotnet-new.md b/docs/azure/includes/dotnet-new.md index 9f5c1f9aab1d9..96d45629c042c 100644 --- a/docs/azure/includes/dotnet-new.md +++ b/docs/azure/includes/dotnet-new.md @@ -86,8 +86,8 @@ | OpenTelemetry Exporter | NuGet [1.4.0](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.Exporter/1.4.0) | [docs](/dotnet/api/overview/azure/Monitor.OpenTelemetry.Exporter-readme) | GitHub [1.4.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Monitor.OpenTelemetry.Exporter_1.4.0/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-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright/1.0.0-beta.1) | | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright/) | -| Playwright NUnit | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright.NUnit/1.0.0-beta.1) | | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright.NUnit_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright.NUnit/) | +| Playwright | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Developer.Playwright-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright/) | +| Playwright NUnit | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Developer.Playwright.NUnit/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Developer.Playwright.NUnit-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Developer.Playwright.NUnit_1.0.0-beta.1/sdk/loadtestservice/Azure.Developer.Playwright.NUnit/) | | Programmable Connectivity | NuGet [1.0.0-beta.1](https://www.nuget.org/packages/Azure.Communication.ProgrammableConnectivity/1.0.0-beta.1) | [docs](/dotnet/api/overview/azure/Communication.ProgrammableConnectivity-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [1.0.0-beta.1](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Communication.ProgrammableConnectivity_1.0.0-beta.1/sdk/communication/Azure.Communication.ProgrammableConnectivity/) | | Provisioning | NuGet [1.1.0](https://www.nuget.org/packages/Azure.Provisioning/1.1.0) | [docs](/dotnet/api/overview/azure/Provisioning-readme) | GitHub [1.1.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Provisioning_1.1.0/sdk/provisioning/Azure.Provisioning/) | | Provisioning - Resources | NuGet [0.2.0](https://www.nuget.org/packages/Azure.Provisioning.Resources/0.2.0) | [docs](/dotnet/api/overview/azure/Provisioning.Resources-readme?view=azure-dotnet-preview&preserve-view=true) | GitHub [0.2.0](https://github.com/Azure/azure-sdk-for-net/tree/Azure.Provisioning.Resources_0.2.0/sdk/provisioning/Azure.Provisioning.Resources/) | diff --git a/docs/azure/sdk/snippets/configure-proxy/ProxyServerConfiguration.csproj b/docs/azure/sdk/snippets/configure-proxy/ProxyServerConfiguration.csproj index ed1dc4ab6e118..fb8102bb29703 100644 --- a/docs/azure/sdk/snippets/configure-proxy/ProxyServerConfiguration.csproj +++ b/docs/azure/sdk/snippets/configure-proxy/ProxyServerConfiguration.csproj @@ -8,7 +8,7 @@ - + diff --git a/docs/csharp/advanced-topics/interop/how-to-use-named-and-optional-arguments-in-office-programming.md b/docs/csharp/advanced-topics/interop/how-to-use-named-and-optional-arguments-in-office-programming.md index b09dfda8d5a22..ad192acb64a5c 100644 --- a/docs/csharp/advanced-topics/interop/how-to-use-named-and-optional-arguments-in-office-programming.md +++ b/docs/csharp/advanced-topics/interop/how-to-use-named-and-optional-arguments-in-office-programming.md @@ -38,6 +38,9 @@ In **Solution Explorer**, right-click the *Program.cs* file and then select **Vi In the `Program` class in *Program.cs*, add the following method to create a Word application and a Word document. The [Add]() method has four optional parameters. This example uses their default values. Therefore, no arguments are necessary in the calling statement. +> [!NOTE] +> To avoid COM threading and timing issues that can cause exceptions like "The message filter indicated that the application is busy" (HRESULT 0x8001010A), the Word application is kept invisible during operations and only made visible after all operations are complete. + :::code language="csharp" source="./snippets/NamedAndOptional/wordprogram.cs" id="Snippet6"::: Add the following code at the end of the method to define where to display text in the document, and what text to display: diff --git a/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/snippets.5000.json b/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/snippets.5000.json index 7aa30d9f5c11d..74059af081788 100644 --- a/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/snippets.5000.json +++ b/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/snippets.5000.json @@ -3,7 +3,7 @@ "expectederrors": [ { "file": "docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/WordProgram.cs", - "line": 8, + "line": 5, "column": 24, "error": "CS0234" } diff --git a/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/wordprogram.cs b/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/wordprogram.cs index 869010da0a10b..9ca8a369f85a9 100644 --- a/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/wordprogram.cs +++ b/docs/csharp/advanced-topics/interop/snippets/NamedAndOptional/wordprogram.cs @@ -19,7 +19,8 @@ static void Main(string[] args) static void DisplayInWord() { var wordApp = new Word.Application(); - wordApp.Visible = true; + // Keep Word invisible during operations to avoid COM threading issues + wordApp.Visible = false; // docs is a collection of all the Document objects currently // open in Word. Word.Documents docs = wordApp.Documents; @@ -61,6 +62,9 @@ static void DisplayInWord() range.ConvertToTable(Separator: ",", AutoFit: true, NumColumns: 1, Format: Word.WdTableFormat.wdTableFormatElegant); // + + // Make Word visible after all operations are complete + wordApp.Visible = true; } } } @@ -74,20 +78,25 @@ class Parts static void DisplayInWord() { var wordApp = new Word.Application(); - wordApp.Visible = true; + // Keep Word invisible during operations to avoid COM threading issues + wordApp.Visible = false; // docs is a collection of all the Document objects currently // open in Word. Word.Documents docs = wordApp.Documents; // Add a document to the collection and name it doc. Word.Document doc = docs.Add(); + + // Make Word visible after operations are complete + wordApp.Visible = true; } // static void VS2008() { var wordApp = new Word.Application(); - wordApp.Visible = true; + // Keep Word invisible during operations to avoid COM threading issues + wordApp.Visible = false; // docs is a collection of all the Document objects currently // open in Word. Word.Documents docs = wordApp.Documents; @@ -101,6 +110,9 @@ static void VS2008() Word.Range range = doc.Range(ref n, ref n); range.InsertAfter("Testing, testing, testing. . ."); + + // Make Word visible after operations are complete + wordApp.Visible = true; } } } diff --git a/docs/csharp/language-reference/keywords/protected.md b/docs/csharp/language-reference/keywords/protected.md index 5d03de0f8df41..b81bbf41809d1 100644 --- a/docs/csharp/language-reference/keywords/protected.md +++ b/docs/csharp/language-reference/keywords/protected.md @@ -26,7 +26,7 @@ A protected member of a base class is accessible in a derived class only if the [!code-csharp[csrefKeywordsModifiers#11](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs#11)] -The statement `a.x = 10` generates an error because it is made within the static method Main, and not an instance of class B. +The statement `a.x = 10` generates an error because it accesses the protected member through a base class reference (`a` is of type `A`). Protected members can only be accessed through the derived class type or types derived from it. Struct members cannot be protected because the struct cannot be inherited. diff --git a/docs/csharp/language-reference/operators/lambda-expressions.md b/docs/csharp/language-reference/operators/lambda-expressions.md index 8d5b3bd6aca96..1b8bd39687187 100644 --- a/docs/csharp/language-reference/operators/lambda-expressions.md +++ b/docs/csharp/language-reference/operators/lambda-expressions.md @@ -49,7 +49,7 @@ A lambda expression with an expression on the right side of the `=>` operator is (input-parameters) => expression ``` -The body of an expression lambda can consist of a method call. However, when creating [expression trees](../../advanced-topics/expression-trees/index.md) evaluated by a query provider, limit method calls to those methods recognized by the query provider. Otherwise, the query provider can't replicate the method's function. +The body of an expression lambda can consist of a method call. However, when creating [expression trees](../../advanced-topics/expression-trees/index.md) evaluated by a query provider, you should limit method calls to those methods that the query provider translates to its format. Different query providers have varying capabilities—for example, many SQL-based providers can translate methods like into appropriate SQL expressions such as `LIKE`. If a query provider doesn't recognize a method call, it can't translate or execute the expression. ## Statement lambdas diff --git a/docs/csharp/language-reference/xmldoc/recommended-tags.md b/docs/csharp/language-reference/xmldoc/recommended-tags.md index 8f3b24554d736..67af2b72f3916 100644 --- a/docs/csharp/language-reference/xmldoc/recommended-tags.md +++ b/docs/csharp/language-reference/xmldoc/recommended-tags.md @@ -118,6 +118,9 @@ Some of the recommended tags can be used on any language element. Others have mo The compiler verifies the syntax of the elements followed by a single \* in the following list. Visual Studio provides IntelliSense for the tags verified by the compiler and all tags followed by \*\* in the following list. In addition to the tags listed here, the compiler and Visual Studio validate the ``, ``, ``, `
`, and `` tags. The compiler also validates ``, which is deprecated HTML. +> [!NOTE] +> HTML tags like `
` are useful for formatting within documentation comments. The `
` tag creates line breaks, while other HTML tags provide text formatting. These tags work in IntelliSense tooltips and generated documentation. + - [General Tags](#general-tags) used for multiple elements - These tags are the minimum set for any API. - [`
`](#summary): The value of this element is displayed in IntelliSense in Visual Studio. - [``](#remarks) \*\* @@ -133,6 +136,11 @@ The compiler verifies the syntax of the elements followed by a single \* in the - [``](#c) - [``](#code) - [``](#example) \*\* + - [``](#b) + - [``](#i) + - [``](#u) + - [`
`](#br) + - [`
`](#a) - [Reuse documentation text](#reuse-documentation-text) - These tags provide tools that make it easier to reuse XML comments. - [``](#inheritdoc) \*\* - [``](#include) \* @@ -241,6 +249,10 @@ The `` tag lets you describe the value that a property represents. When y The `` tag is for use inside a tag, such as [\](#summary), [\](#remarks), or [\](#returns), and lets you add structure to the text. The `` tag creates a double spaced paragraph. Use the `
` tag if you want a single spaced paragraph. +Here's an example showing the difference between `` and `
`: + +:::code language="csharp" source="./snippets/xmldoc/HrefAndBrExamples.cs" id="FormattingExample"::: + ### \ ```xml @@ -303,6 +315,49 @@ This shows how to increment an integer. The `` tag lets you specify an example of how to use a method or other library member. An example commonly involves using the [\](#code) tag. +### \ + +```xml +text +``` + +The `` tag is used to make text bold within documentation comments. This HTML formatting tag is validated by the compiler and Visual Studio, and the formatted text appears in IntelliSense and generated documentation. + +### \ + +```xml +text +``` + +The `` tag is used to make text italic within documentation comments. This HTML formatting tag is validated by the compiler and Visual Studio, and the formatted text appears in IntelliSense and generated documentation. + +### \ + +```xml +text +``` + +The `` tag is used to underline text within documentation comments. This HTML formatting tag is validated by the compiler and Visual Studio, and the formatted text appears in IntelliSense and generated documentation. + +### \
+ +```xml +Line one
Line two +``` + +The `
` tag is used to insert a line break within documentation comments. Use this tag when you want a single spaced paragraph, as opposed to the `` tag which creates double spaced paragraphs. + +### \
+ +```xml +Link text +``` + +The `` tag is used to create hyperlinks within documentation comments. The `href` attribute specifies the URL to link to. This HTML formatting tag is validated by the compiler and Visual Studio. + +> [!NOTE] +> The compiler also validates the `` tag, which is deprecated HTML. Use the [``](#c) tag instead for inline code formatting. + ## Reuse documentation text ### \ @@ -368,11 +423,15 @@ The XML output for this method is shown in the following example: ``` - `cref="member"`: A reference to a member or field that is available to be called from the current compilation environment. The compiler checks that the given code element exists and passes `member` to the element name in the output XML. Place *member* within quotation marks ("). You can provide different link text for a "cref", by using a separate closing tag. -- `href="link"`: A clickable link to a given URL. For example, `GitHub` produces a clickable link with text :::no-loc text="GitHub"::: that links to `https://github.com`. +- `href="link"`: A clickable link to a given URL. For example, `GitHub` produces a clickable link with text :::no-loc text="GitHub"::: that links to `https://github.com`. Use `href` instead of `cref` when linking to external web pages, as `cref` is designed for code references and won't create clickable links for external URLs. - `langword="keyword"`: A language keyword, such as `true` or one of the other valid [keywords](../keywords/index.md). The `` tag lets you specify a link from within text. Use [\](#seealso) to indicate that text should be placed in a See Also section. Use the [cref attribute](#cref-attribute) to create internal hyperlinks to documentation pages for code elements. You include the type parameters to specify a reference to a generic type or method, such as `cref="IDictionary{T, U}"`. Also, ``href`` is a valid attribute that functions as a hyperlink. +Here's an example showing the difference between `cref` and `href` when referencing external URLs: + +:::code language="csharp" source="./snippets/xmldoc/HrefAndBrExamples.cs" id="UrlLinkingExample"::: + ### \ ```xml @@ -392,7 +451,7 @@ The `cref` attribute in an XML documentation tag means "code reference." It spec ### href attribute -The `href` attribute means a reference to a web page. You can use it to directly reference online documentation about your API or library. +The `href` attribute means a reference to a web page. You can use it to directly reference online documentation about your API or library. When you need to link to external URLs in your documentation comments, use `href` instead of `cref` to ensure the links are clickable in IntelliSense tooltips and generated documentation. ## Generic types and methods diff --git a/docs/csharp/language-reference/xmldoc/snippets/xmldoc/HrefAndBrExamples.cs b/docs/csharp/language-reference/xmldoc/snippets/xmldoc/HrefAndBrExamples.cs new file mode 100644 index 0000000000000..3ba7b4df6cf1a --- /dev/null +++ b/docs/csharp/language-reference/xmldoc/snippets/xmldoc/HrefAndBrExamples.cs @@ -0,0 +1,60 @@ +using System; + +namespace XmlDocumentationExamples +{ + /// + /// This class demonstrates the use of href attribute and br tag in XML documentation. + /// + public class HrefAndBrExamples + { + // + /// + /// This method demonstrates URL linking: + /// (won't create clickable link) + /// C# documentation (creates clickable link) + /// + public void UrlLinkingExample() + { + // This method demonstrates the difference between cref and href for URLs + } + // + + // + /// + /// Example using para tags: + /// This is the first paragraph. + /// This is the second paragraph with double spacing. + /// + /// Example using br tags: + /// First line of text
+ /// Second line of text with single spacing
+ /// Third line of text + ///
+ public void FormattingExample() + { + // This method demonstrates paragraph and line break formatting + } + //
+ + /// + /// Comprehensive example showing different link types: + /// Console.WriteLine (code reference with custom text)
+ /// GitHub repository (external link)
+ /// (language keyword)
+ /// (type reference) + ///
+ /// + /// This example shows: + /// + /// Using cref for code elements + /// Using href for external URLs + /// Using langword for language keywords + /// Using br for line breaks in summaries + /// + /// + public void ComprehensiveExample() + { + // This method demonstrates various linking and formatting options + } + } +} \ No newline at end of file diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md index 50967a94e9548..f74873458a7c0 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md @@ -30,6 +30,14 @@ The next example shows the order of execution of constructor and member initiali :::code language="csharp" source="snippets/object-collection-initializers/ObjectInitializersExecutionOrder.cs" id="ObjectInitializersExecutionOrder"::: +## Object initializers without the `new` keyword + +You can also use object initializer syntax without the `new` keyword to initialize properties of nested objects. This syntax is particularly useful with read-only properties: + +:::code language="csharp" source="snippets/object-collection-initializers/ObjectInitializerWithoutNew.cs" id="SnippetObjectInitializerWithoutNew"::: + +This approach modifies the existing instance of the nested object rather than creating a new one. For more details and examples, see [Object Initializers with class-typed properties](object-and-collection-initializers.md#object-initializers-with-class-typed-properties). + ## See also - [Object and Collection Initializers](object-and-collection-initializers.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index a36d6f32e4644..6b86a1001474f 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -19,6 +19,8 @@ Object initializers let you assign values to any accessible fields or properties The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment. +Starting with nested object properties, you can use object initializer syntax without the `new` keyword. This syntax, `Property = { ... }`, allows you to initialize members of existing nested objects, which is particularly useful with read-only properties. For more details, see [Object Initializers with class-typed properties](#object-initializers-with-class-typed-properties). + Object initializers can set indexers, in addition to assigning fields and properties. Consider this basic `Matrix` class: :::code language="csharp" source="./snippets/object-collection-initializers/BasicObjectInitializers.cs" id="MatrixDeclaration"::: @@ -124,11 +126,30 @@ Required init-only properties support immutable structures while allowing natura ## Object Initializers with class-typed properties -It's crucial to consider the implications for class-typed properties when initializing an object: +When initializing objects with class-typed properties, you can use two different syntaxes: + +1. **Object initializer without `new` keyword**: `Property = { ... }` +2. **Object initializer with `new` keyword**: `Property = new() { ... }` + +These syntaxes behave differently. The following example demonstrates both approaches: :::code language="csharp" source="./snippets/object-collection-initializers/HowToClassTypedInitializer.cs" id="HowToClassTypedInitializer"::: -The following example shows how, for ClassB, the initialization process involves updating specific values while retaining others from the original instance. The Initializer reuses current instance: ClassB's values are: `100003` (new value we assign here), `true` (kept from EmbeddedClassTypeA's initialization), `BBBabc` (unchanged default from EmbeddedClassTypeB). +### Key differences + +- **Without `new` keyword** (`ClassB = { BI = 100003 }`): This syntax modifies the existing instance of the property that was created during object construction. It calls member initializers on the existing object. + +- **With `new` keyword** (`ClassB = new() { BI = 100003 }`): This syntax creates a completely new instance and assigns it to the property, replacing any existing instance. + +The initializer without `new` reuses the current instance. In the example above, ClassB's values are: `100003` (new value assigned), `true` (kept from EmbeddedClassTypeA's initialization), `BBBabc` (unchanged default from EmbeddedClassTypeB). + +### Object initializers without `new` for read-only properties + +The syntax without `new` is particularly useful with read-only properties, where you can't assign a new instance but can still initialize the existing instance's members: + +:::code language="csharp" source="./snippets/object-collection-initializers/ObjectInitializerWithoutNew.cs" id="ReadOnlyPropertyExample"::: + +This approach allows you to initialize nested objects even when the containing property doesn't have a setter. ## Collection initializers diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/ObjectInitializerWithoutNew.cs b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/ObjectInitializerWithoutNew.cs new file mode 100644 index 0000000000000..a9689e6974eb9 --- /dev/null +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/ObjectInitializerWithoutNew.cs @@ -0,0 +1,79 @@ +namespace object_collection_initializers; + +// +public class ObjectInitializerWithoutNew +{ + public class Address + { + public string Street { get; set; } = ""; + public string City { get; set; } = ""; + public string State { get; set; } = ""; + } + + public class Person + { + public string Name { get; set; } = ""; + public Address HomeAddress { get; set; } = new(); // Property with setter + } + + public static void Examples() + { + // Example 1: Using object initializer WITHOUT 'new' keyword + // This modifies the existing Address instance created in the constructor + var person1 = new Person + { + Name = "Alice", + HomeAddress = { Street = "123 Main St", City = "Anytown", State = "CA" } + }; + + // Example 2: Using object initializer WITH 'new' keyword + // This creates a completely new Address instance + var person2 = new Person + { + Name = "Bob", + HomeAddress = new Address { Street = "456 Oak Ave", City = "Somewhere", State = "NY" } + }; + + // Both approaches work, but they behave differently: + // - person1.HomeAddress is the same instance that was created in Person's constructor + // - person2.HomeAddress is a new instance, replacing the one from the constructor + + Console.WriteLine($"Person 1: {person1.Name} at {person1.HomeAddress.Street}, {person1.HomeAddress.City}, {person1.HomeAddress.State}"); + Console.WriteLine($"Person 2: {person2.Name} at {person2.HomeAddress.Street}, {person2.HomeAddress.City}, {person2.HomeAddress.State}"); + } +} +// + +// +public class ReadOnlyPropertyExample +{ + public class Settings + { + public string Theme { get; set; } = "Light"; + public int FontSize { get; set; } = 12; + } + + public class Application + { + public string Name { get; set; } = ""; + // This property is read-only - it can only be set during construction + public Settings AppSettings { get; } = new(); + } + + public static void Example() + { + // You can still initialize the nested object's properties + // even though AppSettings property has no setter + var app = new Application + { + Name = "MyApp", + AppSettings = { Theme = "Dark", FontSize = 14 } + }; + + // This would cause a compile error because AppSettings has no setter: + // app.AppSettings = new Settings { Theme = "Dark", FontSize = 14 }; + + Console.WriteLine($"App: {app.Name}, Theme: {app.AppSettings.Theme}, Font Size: {app.AppSettings.FontSize}"); + } +} +// \ No newline at end of file diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/Program.cs b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/Program.cs index c311d44d10821..8a6e4b5746960 100644 --- a/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/Program.cs +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/Program.cs @@ -9,5 +9,9 @@ static void Main(string[] args) HowToIndexInitializer.Main(); HowToDictionaryInitializer.Main(); ObjectInitializersExecutionOrder.Main(); + + Console.WriteLine("\n--- Object Initializer Without New Examples ---"); + ObjectInitializerWithoutNew.Examples(); + ReadOnlyPropertyExample.Example(); } } diff --git a/docs/csharp/programming-guide/concepts/covariance-contravariance/snippets/using-variance-in-delegates/ContravarianceExample.cs b/docs/csharp/programming-guide/concepts/covariance-contravariance/snippets/using-variance-in-delegates/ContravarianceExample.cs new file mode 100644 index 0000000000000..0ab038d2b1b90 --- /dev/null +++ b/docs/csharp/programming-guide/concepts/covariance-contravariance/snippets/using-variance-in-delegates/ContravarianceExample.cs @@ -0,0 +1,133 @@ +using System; + +namespace ContravarianceExample +{ + // + // Custom EventArgs classes to demonstrate the hierarchy + public class KeyEventArgs(string keyCode) : EventArgs + { + public string KeyCode { get; set; } = keyCode; + } + + public class MouseEventArgs(int x, int y) : EventArgs + { + public int X { get; set; } = x; + public int Y { get; set; } = y; + } + + // Define delegate types that match the Windows Forms pattern + public delegate void KeyEventHandler(object sender, KeyEventArgs e); + public delegate void MouseEventHandler(object sender, MouseEventArgs e); + + // A simple class that demonstrates contravariance with events + public class Button + { + // Events that expect specific EventArgs-derived types + public event KeyEventHandler? KeyDown; + public event MouseEventHandler? MouseClick; + + // Method to simulate key press + public void SimulateKeyPress(string key) + { + Console.WriteLine($"Simulating key press: {key}"); + KeyDown?.Invoke(this, new KeyEventArgs(key)); + } + + // Method to simulate mouse click + public void SimulateMouseClick(int x, int y) + { + Console.WriteLine($"Simulating mouse click at ({x}, {y})"); + MouseClick?.Invoke(this, new MouseEventArgs(x, y)); + } + } + + public class Form1 + { + private Button button1; + + public Form1() + { + button1 = new Button(); + + // Event handler that accepts a parameter of the base EventArgs type. + // This method can handle events that expect more specific EventArgs-derived types + // due to contravariance in delegate parameters. + + // You can use a method that has an EventArgs parameter, + // although the KeyDown event expects the KeyEventArgs parameter. + button1.KeyDown += MultiHandler; + + // You can use the same method for an event that expects + // the MouseEventArgs parameter. + button1.MouseClick += MultiHandler; + } + + // Event handler that accepts a parameter of the base EventArgs type. + // This works for both KeyDown and MouseClick events because: + // - KeyDown expects KeyEventHandler(object sender, KeyEventArgs e) + // - MouseClick expects MouseEventHandler(object sender, MouseEventArgs e) + // - Both KeyEventArgs and MouseEventArgs derive from EventArgs + // - Contravariance allows a method with a base type parameter (EventArgs) + // to be used where a derived type parameter is expected + private void MultiHandler(object sender, EventArgs e) + { + Console.WriteLine($"MultiHandler called at: {DateTime.Now:HH:mm:ss.fff}"); + + // You can check the actual type of the event args if needed + switch (e) + { + case KeyEventArgs keyArgs: + Console.WriteLine($" - Key event: {keyArgs.KeyCode}"); + break; + case MouseEventArgs mouseArgs: + Console.WriteLine($" - Mouse event: ({mouseArgs.X}, {mouseArgs.Y})"); + break; + default: + Console.WriteLine($" - Generic event: {e.GetType().Name}"); + break; + } + } + + public void DemonstrateEvents() + { + Console.WriteLine("Demonstrating contravariance in event handlers:"); + Console.WriteLine("Same MultiHandler method handles both events!\n"); + + button1.SimulateKeyPress("Enter"); + button1.SimulateMouseClick(100, 200); + button1.SimulateKeyPress("Escape"); + button1.SimulateMouseClick(50, 75); + } + } + // + + // + // Demonstration of how contravariance works with delegates: + // + // 1. KeyDown event signature: KeyEventHandler(object sender, KeyEventArgs e) + // where KeyEventArgs derives from EventArgs + // + // 2. MouseClick event signature: MouseEventHandler(object sender, MouseEventArgs e) + // where MouseEventArgs derives from EventArgs + // + // 3. Our MultiHandler method signature: MultiHandler(object sender, EventArgs e) + // + // 4. Contravariance allows us to use MultiHandler (which expects EventArgs) + // for events that provide more specific types (KeyEventArgs, MouseEventArgs) + // because the more specific types can be safely treated as their base type. + // + // This is safe because: + // - The MultiHandler only uses members available on the base EventArgs type + // - KeyEventArgs and MouseEventArgs can be implicitly converted to EventArgs + // - The compiler knows that any EventArgs-derived type can be passed safely + // + + class Program + { + static void Main() + { + var form = new Form1(); + form.DemonstrateEvents(); + } + } +} \ No newline at end of file diff --git a/docs/csharp/programming-guide/concepts/covariance-contravariance/snippets/using-variance-in-delegates/ContravarianceExample.csproj b/docs/csharp/programming-guide/concepts/covariance-contravariance/snippets/using-variance-in-delegates/ContravarianceExample.csproj new file mode 100644 index 0000000000000..2dfe8aaebbfb1 --- /dev/null +++ b/docs/csharp/programming-guide/concepts/covariance-contravariance/snippets/using-variance-in-delegates/ContravarianceExample.csproj @@ -0,0 +1,9 @@ + + + + Exe + net9.0 + enable + + + \ No newline at end of file diff --git a/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-delegates.md b/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-delegates.md index b46825554d8bb..86e414362d491 100644 --- a/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-delegates.md +++ b/docs/csharp/programming-guide/concepts/covariance-contravariance/using-variance-in-delegates.md @@ -51,43 +51,41 @@ class Program This example demonstrates how delegates can be used with methods that have parameters whose types are base types of the delegate signature parameter type. With contravariance, you can use one event handler instead of separate handlers. The following example makes use of two delegates: -- A delegate that defines the signature of the [Button.KeyDown](xref:System.Windows.Forms.Control.KeyDown) event. Its signature is: +- A custom `KeyEventHandler` delegate that defines the signature of a key event. Its signature is: ```csharp public delegate void KeyEventHandler(object sender, KeyEventArgs e) ``` -- A delegate that defines the signature of the [Button.MouseClick](xref:System.Windows.Forms.Control.MouseDown) event. Its signature is: +- A custom `MouseEventHandler` delegate that defines the signature of a mouse event. Its signature is: ```csharp public delegate void MouseEventHandler(object sender, MouseEventArgs e) ``` -The example defines an event handler with an parameter and uses it to handle both the `Button.KeyDown` and `Button.MouseClick` events. It can do this because is a base type of both and . +The example defines an event handler with an parameter and uses it to handle both key and mouse events. This works because is a base type of both the custom `KeyEventArgs` and `MouseEventArgs` classes defined in the example. Contravariance allows a method that accepts a base type parameter to be used for events that provide derived type parameters. + +### How contravariance works in this example + +When you subscribe to an event, the compiler checks if your event handler method is compatible with the event's delegate signature. With contravariance: + +1. The `KeyDown` event expects a method that takes `KeyEventArgs`. +1. The `MouseClick` event expects a method that takes `MouseEventArgs`. +1. Your `MultiHandler` method takes the base type `EventArgs`. +1. Since `KeyEventArgs` and `MouseEventArgs` both inherit from `EventArgs`, they can be safely passed to a method expecting `EventArgs`. +1. The compiler allows this assignment because it's safe - the `MultiHandler` can work with any `EventArgs` instance. + +This is contravariance in action: you can use a method with a "less specific" (base type) parameter where a "more specific" (derived type) parameter is expected. ### Code - -```csharp -// Event handler that accepts a parameter of the EventArgs type. -private void MultiHandler(object sender, System.EventArgs e) -{ - label1.Text = System.DateTime.Now.ToString(); -} - -public Form1() -{ - InitializeComponent(); - - // You can use a method that has an EventArgs parameter, - // although the event expects the KeyEventArgs parameter. - this.button1.KeyDown += this.MultiHandler; - - // You can use the same method - // for an event that expects the MouseEventArgs parameter. - this.button1.MouseClick += this.MultiHandler; - -} -``` + +:::code language="csharp" source="snippets/using-variance-in-delegates/ContravarianceExample.cs" id="snippet1"::: + +### Key points about contravariance + +:::code language="csharp" source="snippets/using-variance-in-delegates/ContravarianceExample.cs" id="snippet2"::: + +When you run this example, you'll see that the same `MultiHandler` method successfully handles both key and mouse events, demonstrating how contravariance enables more flexible and reusable event handling code. ## See also diff --git a/docs/csharp/programming-guide/delegates/using-delegates.md b/docs/csharp/programming-guide/delegates/using-delegates.md index 4384e3aa7ff15..5b13037172f43 100644 --- a/docs/csharp/programming-guide/delegates/using-delegates.md +++ b/docs/csharp/programming-guide/delegates/using-delegates.md @@ -19,7 +19,7 @@ A delegate object is normally constructed by providing the name of the method th Delegate types are derived from the class in .NET. Delegate types are [sealed](../../language-reference/keywords/sealed.md), they can't be derived from, and it isn't possible to derive custom classes from . Because the instantiated delegate is an object, it can be passed as an argument, or assigned to a property. A method can accept a delegate as a parameter, and call the delegate at some later time. This is known as an asynchronous callback, and is a common method of notifying a caller when a long process completes. When a delegate is used in this fashion, the code using the delegate doesn't need any knowledge of the implementation of the method being used. The functionality is similar to the encapsulation interfaces provide. -Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. It allows the caller's code to become part of the sort algorithm. The following example method uses the `Del` type as a parameter: +Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. It allows the caller's code to become part of the sort algorithm. The following example method uses the `Callback` type as a parameter: :::code language="csharp" source="./snippets/UsingDelegates.cs" id="DelegateParameter"::: diff --git a/docs/csharp/programming-guide/statements-expressions-operators/expression-bodied-members.md b/docs/csharp/programming-guide/statements-expressions-operators/expression-bodied-members.md index c5d83bfb878aa..d5969b1f9e188 100644 --- a/docs/csharp/programming-guide/statements-expressions-operators/expression-bodied-members.md +++ b/docs/csharp/programming-guide/statements-expressions-operators/expression-bodied-members.md @@ -29,7 +29,7 @@ Expression body definitions can be used with the following type members: An expression-bodied method consists of a single expression that returns a value whose type matches the method's return type, or, for methods that return `void`, that performs some operation. For example, types that override the method typically include a single expression that returns the string representation of the current object. -The following example defines a `Person` class that overrides the method with an expression body definition. It also defines a `DisplayName` method that displays a name to the console. The `return` keyword is not used in the `ToString` expression body definition. +The following example defines a `Person` class that overrides the method with an expression body definition. It also defines a `DisplayName` method that displays a name to the console. Additionally, it includes several methods that take parameters, demonstrating how expression-bodied members work with method parameters. The `return` keyword is not used in any of the expression body definitions. [!code-csharp[expression-bodied-methods](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-methods.cs)] @@ -69,7 +69,7 @@ For more information about events, see [Events (C# Programming Guide)](../events An expression body definition for a constructor typically consists of a single assignment expression or a method call that handles the constructor's arguments or initializes instance state. -The following example defines a `Location` class whose constructor has a single string parameter named *name*. The expression body definition assigns the argument to the `Name` property. +The following example defines a `Location` class whose constructor has a single string parameter named *name*. The expression body definition assigns the argument to the `Name` property. The example also shows a `Point` class with constructors that take multiple parameters, demonstrating how expression-bodied constructors work with different parameter combinations. [!code-csharp[expression-bodied-constructor](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-ctor.cs#1)] diff --git a/docs/csharp/tutorials/working-with-linq.md b/docs/csharp/tutorials/working-with-linq.md index 68f700d45b431..c8ffb58e4f5fa 100644 --- a/docs/csharp/tutorials/working-with-linq.md +++ b/docs/csharp/tutorials/working-with-linq.md @@ -47,6 +47,9 @@ using System.Linq; If these three lines (`using` directives) aren't at the top of the file, your program might not compile. +> [!TIP] +> For this tutorial, you can organize your code in a namespace called `LinqFaroShuffle` to match the sample code, or you can use the default global namespace. If you choose to use a namespace, make sure all your classes and methods are consistently within the same namespace, or add appropriate `using` statements as needed. + Now that you have all of the references that you'll need, consider what constitutes a deck of cards. Commonly, a deck of playing cards has four suits, and each suit has thirteen values. Normally, you might consider creating a `Card` class right off the bat and populating a collection of `Card` objects by hand. With LINQ, you can be more concise than the usual way of dealing with creating a deck of cards. Instead of creating a `Card` class, you can create two sequences to represent suits and ranks, respectively. You'll create a really simple pair of [*iterator methods*](../iterators.md#enumeration-sources-with-iterator-methods) that will generate the ranks and suits as s of strings: ```csharp @@ -160,6 +163,9 @@ namespace LinqFaroShuffle } ``` +> [!NOTE] +> If you're using an editor other than Visual Studio (such as Visual Studio Code), you might need to add `using LinqFaroShuffle;` to the top of your _Program.cs_ file for the extension methods to be accessible. Visual Studio automatically adds this using statement, but other editors might not. + Look at the method signature for a moment, specifically the parameters: ```csharp diff --git a/docs/standard/linq/preserve-white-space-serializing.md b/docs/standard/linq/preserve-white-space-serializing.md index 714b546cb125c..7d14477145f43 100644 --- a/docs/standard/linq/preserve-white-space-serializing.md +++ b/docs/standard/linq/preserve-white-space-serializing.md @@ -25,3 +25,31 @@ The following methods in the and as an argument, then the method will format (indent) the serialized XML. In this case, all insignificant white space in the XML tree is discarded. If the method does take as an argument, then you can specify that the method not format (indent) the serialized XML. In this case, all white space in the XML tree is preserved. + +## Roundtripping XML with carriage return entities + +The whitespace preservation discussed in this article is different from XML roundtripping. When XML contains carriage return entities (` `), LINQ to XML's standard serialization might not preserve them in a way that allows perfect roundtripping. + +Consider the following example XML that contains carriage return entities: + +```xml +a +b +c +``` + +When you parse this XML with `XDocument.Parse()`, the root element's value becomes `"a\r\nb\nc\r"`. However, if you reserialize it using LINQ to XML methods, the carriage returns are not entitized: + +:::code language="csharp" source="snippets/preserve-white-space-serializing/RoundtrippingProblem.cs" Id="XmlRoundTrip"::: + +The values are different: the original was `"a\r\nb\nc\r"` but after roundtripping it becomes `"a\nb\nc\n"`. + +### Solution: Use XmlWriter with NewLineHandling.Entitize + +To achieve true XML roundtripping that preserves carriage return entities, use with set to : + +:::code language="csharp" source="snippets/preserve-white-space-serializing/RoundtrippingSolution.cs" Id="XmlRoundTripFix"::: + +When you need to preserve carriage return entities for XML roundtripping, use with the appropriate instead of LINQ to XML's built-in serialization methods. + +For more information about and its settings, see . diff --git a/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingProblem.cs b/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingProblem.cs new file mode 100644 index 0000000000000..81637b26f46c4 --- /dev/null +++ b/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingProblem.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq; +using System.Xml.Linq; + +class Program +{ + static void Main() + { + Console.WriteLine("XML Roundtripping Examples"); + Console.WriteLine("=========================="); + + Console.WriteLine("\n1. Roundtripping Problem:"); + RoundtrippingProblem.Example(); + + Console.WriteLine("\n2. Roundtripping Solution:"); + RoundtrippingSolution.Example(); + } +} + +public static class RoundtrippingProblem +{ + public static void Example() + { + // + string xmlWithCR = """ + a + b + c + """; + + XDocument doc = XDocument.Parse(xmlWithCR); + Console.WriteLine($"Original parsed value: {string.Join("", doc.Root!.Value.Select(c => c == '\r' ? "\\r" : c == '\n' ? "\\n" : c.ToString()))}"); + // Output: a\r\nb\nc\r + + string reserialized = doc.ToString(SaveOptions.DisableFormatting); + Console.WriteLine($"Reserialized XML: {reserialized}"); + // Output: a + // b + // c + + XDocument reparsed = XDocument.Parse(reserialized); + Console.WriteLine($"Reparsed value: {string.Join("", reparsed.Root!.Value.Select(c => c == '\r' ? "\\r" : c == '\n' ? "\\n" : c.ToString()))}"); + // Output: a\nb\nc\n + // + } +} \ No newline at end of file diff --git a/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingSolution.cs b/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingSolution.cs new file mode 100644 index 0000000000000..04edd2e585cb4 --- /dev/null +++ b/docs/standard/linq/snippets/preserve-white-space-serializing/RoundtrippingSolution.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Xml; +using System.Xml.Linq; + +public static class RoundtrippingSolution +{ + public static void Example() + { + // + string xmlWithCR = """ + a + b + c + """; + + XDocument doc = XDocument.Parse(xmlWithCR); + + // Create XmlWriter settings with NewLineHandling.Entitize + XmlWriterSettings settings = new XmlWriterSettings + { + NewLineHandling = NewLineHandling.Entitize, + OmitXmlDeclaration = true + }; + + // Serialize using XmlWriter + using StringWriter stringWriter = new StringWriter(); + using (XmlWriter writer = XmlWriter.Create(stringWriter, settings)) + { + doc.WriteTo(writer); + } + + string roundtrippedXml = stringWriter.ToString(); + Console.WriteLine($"Roundtripped XML: {roundtrippedXml}"); + // Output: a + // b + // c + + // Verify roundtripping preserves the original value + XDocument roundtrippedDoc = XDocument.Parse(roundtrippedXml); + bool valuesMatch = doc.Root!.Value == roundtrippedDoc.Root!.Value; + Console.WriteLine($"Values match after roundtripping: {valuesMatch}"); + // + // Output: True + } +} \ No newline at end of file diff --git a/docs/standard/linq/snippets/preserve-white-space-serializing/preserve-white-space-serializing.csproj b/docs/standard/linq/snippets/preserve-white-space-serializing/preserve-white-space-serializing.csproj new file mode 100644 index 0000000000000..c28018dbfdd4c --- /dev/null +++ b/docs/standard/linq/snippets/preserve-white-space-serializing/preserve-white-space-serializing.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + \ No newline at end of file diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs index 73ac9eac4848d..7c058a3e6ab73 100644 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs +++ b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs @@ -345,8 +345,8 @@ static void Main() var a = new A(); var b = new B(); - // Error CS1540, because x can only be accessed by - // classes derived from A. + // Error CS1540, because x can only be accessed through + // the derived class type, not through the base class type. // a.x = 10; // OK, because this class derives from A. diff --git a/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/Program.cs b/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/Program.cs index eec3e146d76a5..3ae6c746e7ace 100644 --- a/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/Program.cs +++ b/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/Program.cs @@ -1,2 +1,2 @@ // See https://aka.ms/new-console-template for more information -ExprBodied.Example.Main(); +ExpressionBodiedMembers.Example.Main(); diff --git a/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-ctor.cs b/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-ctor.cs index 1eccae545ad87..e43962db2811e 100644 --- a/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-ctor.cs +++ b/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-ctor.cs @@ -15,6 +15,19 @@ public string Name set => locationName = value; } } + +// Example with multiple parameters +public class Point +{ + public double X { get; } + public double Y { get; } + + // Constructor with multiple parameters + public Point(double x, double y) => (X, Y) = (x, y); + + // Constructor with single parameter (creates point at origin on axis) + public Point(double coordinate) => (X, Y) = (coordinate, 0); +} // public class Example @@ -23,5 +36,11 @@ public static void Main() { var city = new Location("New York City"); Console.WriteLine(city.Name); + + // Examples with multiple constructor parameters + var point1 = new Point(3.0, 4.0); + var point2 = new Point(5.0); + Console.WriteLine($"Point 1: ({point1.X}, {point1.Y})"); + Console.WriteLine($"Point 2: ({point2.X}, {point2.Y})"); } } \ No newline at end of file diff --git a/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-methods.cs b/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-methods.cs index b71dd73ea70ab..a11b3f27a94f9 100644 --- a/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-methods.cs +++ b/samples/snippets/csharp/programming-guide/classes-and-structs/ExpressionBodiedMembers/expr-bodied-methods.cs @@ -15,14 +15,26 @@ public Person(string firstName, string lastName) public override string ToString() => $"{fname} {lname}".Trim(); public void DisplayName() => Console.WriteLine(ToString()); + + // Expression-bodied methods with parameters + public string GetFullName(string title) => $"{title} {fname} {lname}"; + public int CalculateAge(int birthYear) => DateTime.Now.Year - birthYear; + public bool IsOlderThan(int age) => CalculateAge(1990) > age; + public string FormatName(string format) => format.Replace("{first}", fname).Replace("{last}", lname); } class Example { - static void Main() + public static void Main() { Person p = new Person("Mandy", "Dejesus"); Console.WriteLine(p); p.DisplayName(); + + // Examples with parameters + Console.WriteLine(p.GetFullName("Dr.")); + Console.WriteLine($"Age: {p.CalculateAge(1990)}"); + Console.WriteLine($"Is older than 25: {p.IsOlderThan(25)}"); + Console.WriteLine(p.FormatName("Last: {last}, First: {first}")); } }