{"id":8707,"date":"2025-03-13T11:44:00","date_gmt":"2025-03-13T10:44:00","guid":{"rendered":"https:\/\/www.fores.group\/?p=8707"},"modified":"2025-09-14T14:13:24","modified_gmt":"2025-09-14T12:13:24","slug":"efficient-collection-management-in-c-optimize-your-code-performance","status":"publish","type":"post","link":"https:\/\/www.fores.group\/sk\/efficient-collection-management-in-c-optimize-your-code-performance\/","title":{"rendered":"<span id=\"text_part1\">My favorite C# features in<\/span> <span  id=\"text_part2\">real world use cases<\/span>"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"8707\" class=\"elementor elementor-8707\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4554ff23 e-flex e-con-boxed e-con e-parent\" data-id=\"4554ff23\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-15534a51 elementor-widget elementor-widget-text-editor\" data-id=\"15534a51\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>13. March 2025\u00a0 |\u00a0 Tech Insights by Pavol Mr\u00e1z\u00a0 |\u00a0\u00a0<\/strong><span style=\"text-align: var(--text-align);\"><span style=\"font-weight: bolder;\">CTO:\u00a0<\/span><\/span><span style=\"text-align: var(--text-align);\">My favorite C# features\u00a0<\/span><span style=\"text-align: var(--text-align);\">in real world use cases<\/span><\/p><h1>Introduction<\/h1><p>I have read a ton of articles about someone\u2019s favorite C# language features on the Internet (especially on <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/medium.com\/\" target=\"_blank\" rel=\"noopener\">medium.com<\/a><\/span>) and some of them are really good and inspiring. I\u00a0have decided that I\u00a0might add two cents to the discussion, and this is my take on the subject. It is a\u00a0little bit different than the others, because I present real-world usage patterns, stemmed from our large code base (980+ KLOC) that is undergoing continuous development for more than nine years now (January, 2025). The code base is kind of a <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/www.geeksforgeeks.org\/what-is-a-modular-monolith\/\" target=\"_blank\" rel=\"noopener\">modular monolith<\/a> <\/span>comprised of several business applications, APIs, as well as some reusable functionality in the form of NuGet packages.<\/p><p>In the discussion and code examples below, I have renamed some of the code artifacts, but the actual usage patterns remained intact. I have not tried to restate what the official documentation says, instead, I am providing links to its relevant sections. I\u00a0emphasize here that these are my subjective opinions, and not all my colleagues agree with me 100%.<\/p><h1>Field keyword<\/h1><p>The <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/keywords\/field\" target=\"_blank\" rel=\"noopener\">contextual field keyword<\/a><\/span> can be used in property accessors to access the compiler-generated backing field of a property. We have been using it mostly to add validation to property setters implemented originally as <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/auto-implemented-properties\" target=\"_blank\" rel=\"noopener\">auto-properties<\/a><\/span>. For example, we had this code before introducing the field keyword:<\/p><pre><code>class Person\n{\n public string Name { get; set; }\n}<\/code><\/pre><p>After gradually introducing nullability to our code base, we were able to add property setter validation easily using the field keyword like this:<\/p><pre><code>class Person\n{\n public string Name { get; set { field = value ?? throw new ArgumentNullException(nameof(value)); } } = \"\";\n}<\/code><\/pre><p>Please note that the <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/keywords\/field\" target=\"_blank\" rel=\"noopener\">official documentation<\/a><\/span> says that:<\/p><p><strong>\u201cThe field keyword is a preview feature in C# 13. You must be using .NET 9 and set your &lt;LangVersion&gt; element to preview in your project file in order to use the field contextual keyword.\u201d<\/strong><\/p><p>However, we have been using it in projects targeting netstandard2.0 without problems just with the &lt;LangVersion&gt;preview&lt;\/LangVersion&gt; property set in .csproj (or Directory.Build.props file). This is understandable, because the field keyword is just a syntactic sugar allowing us to access the backing field without needing to know the actual compiler-generated mangled name as <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/gist.github.com\/PaloMraz\/c005731413ea9cc753689bf00353bed4\" target=\"_blank\" rel=\"noopener\">this gist<\/a><\/span> from <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/sharplab.io\/\" target=\"_blank\" rel=\"noopener\">sharplab.io<\/a><\/span> illustrates.<\/p><p><strong>Bonus chatter:<\/strong> First time I have used this feature, I wrote the code this way (note the property name in the setter):<\/p><pre><code>class Person\n{\n public string Name { get; set { Name = value ?? throw new ArgumentNullException(nameof(value)); } } = \"\";\n}<\/code><\/pre><p>Neither the compiler nor any of the analyzers warned me, so I realized the mistake only after running the program and getting an StackOverflowException upon the very first Name property assignment. Now it is obvious that referencing the Name property inside the property setter method creates infinite recursion and I honestly do not know, what led me to write it that way.<\/p><p><img fetchpriority=\"high\" decoding=\"async\" class=\"alignnone wp-image-12871 size-full\" src=\"https:\/\/www.fores.group\/wp-content\/uploads\/2025\/08\/C-Sharp-Blog.png\" alt=\"\" width=\"1182\" height=\"664\" srcset=\"https:\/\/www.fores.group\/wp-content\/uploads\/2025\/08\/C-Sharp-Blog.png 1182w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/08\/C-Sharp-Blog-300x169.png 300w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/08\/C-Sharp-Blog-1024x575.png 1024w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/08\/C-Sharp-Blog-768x431.png 768w\" sizes=\"(max-width: 1182px) 100vw, 1182px\" \/><\/p><h1>Pattern matching and switch expressions<\/h1><p>This feature was first introduced in <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-version-history#c-version-70\" target=\"_blank\" rel=\"noopener\">C# version 7.0<\/a><\/span> but since then, it has been gradually enhanced in almost all subsequent releases, including <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/switch-expression\" target=\"_blank\" rel=\"noopener\">switch expressions<\/a><\/span> in <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-version-history#c-version-80\" target=\"_blank\" rel=\"noopener\">C# version 8.0<\/a><\/span>. We have been using it mostly when working with enums, because the compiler ensures that we always cover all possible enum values (the switch expression is exhaustive as they call it). All but one of the usage patterns I have found use <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#constant-pattern\" target=\"_blank\" rel=\"noopener\">constant pattern<\/a><\/span> matching mapping from enum to some other value. For example, mapping from MqttNetLogLevel (from the excellent <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/www.nuget.org\/packages\/MQTTnet\" target=\"_blank\" rel=\"noopener\">MQTTnet<\/a><\/span> library) to Microsoft\u2019s standard LogLevel:<\/p><pre><code>using Microsoft.Extensions.Logging;\nusing MQTTnet.Diagnostics;\n...\nLogLevel netLogLevel = logLevel switch\n{\n MqttNetLogLevel.Error =&gt; LogLevel.Error,\n MqttNetLogLevel.Warning =&gt; LogLevel.Warning,\n MqttNetLogLevel.Info =&gt; LogLevel.Information,\n MqttNetLogLevel.Verbose =&gt; LogLevel.Trace,\n _ =&gt; LogLevel.Debug\n};<\/code><\/pre><p>The exhaustive mapping can be illustrated by omitting the last line with the discard expression \u201c_ =&gt; LogLevel.Debug\u201d. The then complains with a clear explanation:<strong> error CS8524: <\/strong>The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern &#8218;(MQTTnet.Diagnostics.MqttNetLogLevel)4&#8216; is not covered.<\/p><p>The only other switch expression not using the constant pattern over enum, but based on a <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/operators\/patterns#relational-patterns\" target=\"_blank\" rel=\"noopener\">relational pattern matching<\/a><\/span> expression I found in the code base was in a <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/maui\/what-is-maui\" target=\"_blank\" rel=\"noopener\">MAUI<\/a><\/span> Android application. The application uses GPS for location tracking and maps the <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/developer.android.com\/reference\/android\/location\/Location#getAccuracy()\" target=\"_blank\" rel=\"noopener\">horizontal location accuracy<\/a><\/span> from meters to application-defined enumeration like this:<\/p><pre><code>public enum GpsLocationQuality\n{\n  Unknown = 0,\n  Poor = 1,\n  Good = 2,\n  Excellent = 3\n}\n...\nAndroid.Locations.Location location = &lt;get location from ILocationListener&gt;\nGpsLocationQuality quality = location.Accuracy switch\n{\n  &lt;= 0 =&gt; GpsLocationQuality.Unknown,\n  &lt; 5 =&gt; GpsLocationQuality.Excellent,\n  &lt;= 15 =&gt; GpsLocationQuality.Good,\n  _ =&gt; GpsLocationQuality.Poor\n};<\/code><\/pre><p>Please note that when we omit the last discard expression, the compiler still enforces the exhaustive mapping by giving us the following error:<\/p><pre><code>error CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '15.000001F' is not covered<\/code><\/pre><h1>Raw string literals<\/h1><p>The <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-version-history#c-version-11\" target=\"_blank\" rel=\"noopener\">Raw string literals<\/a><\/span> feature was introduced in C# 11 and I did find just one use case in our code base that I have actually implemented myself \ud83d\ude0a. It was as a portion of integration test suite for legacy SOAP asmx API that was migrated to ASP.NET Core (using the excellent <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/www.nuget.org\/packages\/SoapCore\" target=\"_blank\" rel=\"noopener\">SoapCore<\/a> <\/span>package). I have used a testing approach similar to what Michael feathers calls \u201ccharacterization testing\u201d in his excellent book \u201c<span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/www.amazon.com\/Working-Effectively-Legacy-Michael-Feathers\/dp\/0131177052\" target=\"_blank\" rel=\"noopener\">Working Effectively with Legacy Code<\/a><\/span>\u201d:<\/p><ul><li>I have captured the response XML payloads returned by invoking the legacy SOAP endpoints over a seed database.<\/li><li>I have written tests that invoked the new ASP.NET Core endpoints (over the same seed database) and compared the XML payloads with the captured legacy ones.<\/li><\/ul><p>For the payload comparison, I have used the <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/www.nuget.org\/packages\/XMLUnit.Core\" target=\"_blank\" rel=\"noopener\">XMLUnit.Core<\/a><\/span> package and the legacy response I have put directly into the test code using raw string literals like this:<\/p><pre><code>[Fact]\npublic async Task Verify_SomeService_response()\n{\n  string expectedXmlResponse =\n\"\"\"\n&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\n&lt;soap:Envelope\nxmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\"\nxmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\nxmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;\n&lt;soap:Body&gt;\n&lt;endOfDayResponse\nxmlns=\"http:\/\/example.com\/common\/service\/types\/SomeService\/1.0\"&gt;\n \u00a0\u00a0\u00a0\u00a0 &lt;manifestPDF\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 xmlns=\"\"&gt;some value\n \u00a0\u00a0\u00a0\u00a0 &lt;\/manifestPDF&gt;\n&lt;\/endOfDayResponse&gt;\n&lt;\/soap:Body&gt;\n&lt;\/soap:Envelope&gt;\n\"\"\";\n  string soapCoreXmlResponse = await InvokeSoapCoreServiceAsync(&lt;hardcoded parameters&gt;);\n  var diff = DiffBuilder\n \u00a0\u00a0\u00a0 .Compare(expectedXmlResponse)\n \u00a0\u00a0\u00a0 .WithTest(soapCoreXmlResponse)\n \u00a0\u00a0\u00a0 .IgnoreWhitespace()\n \u00a0\u00a0\u00a0 .Build();\n\u00a0\u00a0 Assert.False(diff.HasDifferences());<\/code><\/pre><p>By using raw string literals, I was able to copy the legacy SOAP payloads directly from <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/www.postman.com\/downloads\/\" target=\"_blank\" rel=\"noopener\">Postman<\/a><\/span> response bodies and paste them into the test methods verbatim.<\/p><p><img decoding=\"async\" class=\"alignnone wp-image-9153 size-full\" src=\"https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1443\" srcset=\"https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-scaled.jpg 2560w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-300x169.jpg 300w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-1024x577.jpg 1024w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-768x433.jpg 768w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-1536x866.jpg 1536w, https:\/\/www.fores.group\/wp-content\/uploads\/2025\/03\/Csharp-III-2048x1154.jpg 2048w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/p><h1>Records, init properties, deconstruction<\/h1><p>The<span style=\"color: #00aaf0;\"> <a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/builtin-types\/record\" target=\"_blank\" rel=\"noopener\">records feature<\/a><\/span> introduced in <span style=\"color: #00aaf0;\"><a style=\"color: #00aaf0;\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-version-history#c-version-9\" target=\"_blank\" rel=\"noopener\">C# 9.0<\/a><\/span> we have been using almost exclusively as a convenient way to define<span style=\"color: #00aaf0;\"> <a style=\"color: #00aaf0;\" href=\"https:\/\/en.wikipedia.org\/wiki\/Data_transfer_object\" target=\"_blank\" rel=\"noopener\">data transfer objects<\/a><\/span>. The automatic read-only property declaration when using records with primary constructors makes them very convenient and terse (and elegant IMHO):<\/p><pre><code>public record class GrantAccessTokenRequestModel(\n \u00a0 string UserName,\n \u00a0 string Password,\n\u00a0\u00a0 string ClientId);<\/code><\/pre><p>The declaration creates an immutable record type and with the help of deconstruction using the with keyword, we can create clones at will:<\/p><pre><code>var requestModel = new GrantAccessTokenRequestModel(\n    UserName: form[RequestFormKeys.UserName],\n    Password: form[RequestFormKeys.Password],\n    ClientId: form[RequestFormKeys.ClientId]);\nvar clone = requestModel with { Password = \"********\" };<\/code><\/pre><p>In order to customize serialization of these record instances, we tend to do that by appropriate application of the JsonPropertyNameAttribute, along with \u00a0init and required C# attributes, for example:<\/p><pre><code>  public record class GrantAccessTokenResponseModel\n  {\n \u00a0\u00a0 [JsonPropertyName(\"access_token\")]\n \u00a0\u00a0 public required string AccessToken { get; init; }\n \u00a0\u00a0 [JsonPropertyName(\"refresh_token\")]\n \u00a0\u00a0 public required string RefreshToken { get; init; }\n \u00a0\u00a0 [JsonPropertyName(\"expires_in\")]\n \u00a0\u00a0 public required int ExpiresInMinutes { get; init; }\n \u00a0\u00a0 [JsonPropertyName(\"token_type\")]\n \u00a0\u00a0 public string TokenType { get; } = \"Bearer\";\n\u00a0 }<\/code><\/pre><p>The above declaration ensures proper serialization to JSON using the specified JSON property names. The declaration also states that the AccessToken, RefreshToken and ExpiresInMinutes properties must be initialized upon construction, for example:<\/p><pre><code>var response = new GrantAccessTokenResponseModel()\n {\n \u00a0 AccessToken = accessTokenString,\n \u00a0 ExpiresInMinutes = (int)(expirationTimeUtc - DateTime.UtcNow).TotalMinutes,\n \u00a0 RefreshToken = refreshToken\n\u00a0};<\/code><\/pre><pre><code>var response = new GrantAccessTokenResponseModel()\n {\n \u00a0 AccessToken = accessTokenString,\n \u00a0 ExpiresInMinutes = (int)(expirationTimeUtc - DateTime.UtcNow).TotalMinutes,\n \u00a0 RefreshToken = refreshToken\n\u00a0};<\/code><\/pre><p>Please note that we use the record class declaration with the class keyword to make it explicit that we are declaring a\u00a0reference type (not the record struct value type).<\/p><p>Author: <strong>Pavol Mr\u00e1z\u00a0 |\u00a0 Chief Technology Officer:<\/strong><\/p><p><em>Throughout his professional career, he has contributed to the design, development, and maintenance of customer information systems for both private and public sector companies, as well as corporate tools and methodologies aimed at streamlining software development.\u00a0<\/em><\/p><p><em>Examples include the service software for the voting system of the Slovak Parliament, the system for tracking technical changes for Volkswagen Slovakia, and the corporate authorization framework Constable.<\/em><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>The article presents my personal take on some of my favorite C# language features, focusing on real-world usage patterns found in a large code base. It provides practical examples of how these features are used by my team in actual development with links to official documentation.<\/p>\n","protected":false},"author":16,"featured_media":9198,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[82],"tags":[],"class_list":["post-8707","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-zmena-procesu"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/posts\/8707","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/comments?post=8707"}],"version-history":[{"count":10,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/posts\/8707\/revisions"}],"predecessor-version":[{"id":15038,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/posts\/8707\/revisions\/15038"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/media\/9198"}],"wp:attachment":[{"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/media?parent=8707"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/categories?post=8707"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fores.group\/sk\/wp-json\/wp\/v2\/tags?post=8707"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}