<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ C# - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ C# - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 18 May 2026 22:34:40 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/csharp/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Query Data in DynamoDB Using .Net ]]>
                </title>
                <description>
                    <![CDATA[ If you're coming to DynamoDB from a relational background, the first thing to understand is this: it's a completely different way of thinking. DynamoDB isn't a relational database, it's a NoSQL key-va ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-query-data-in-dynamodb-using-net/</link>
                <guid isPermaLink="false">69fa1ffca386d7f121b4955b</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ DynamoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dotnet ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Tue, 05 May 2026 16:51:08 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/66b52b176a1b17f6b28d9822/93c4db14-f870-47d6-99c9-e0816d8b628b.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're coming to DynamoDB from a relational background, the first thing to understand is this: it's a completely different way of thinking.</p>
<p>DynamoDB isn't a relational database, it's a NoSQL key-value and document store. You don't write arbitrary queries against your data. Instead, you design your tables around the specific access patterns your application needs.</p>
<p>DynamoDB is driven by your queries, not your data.</p>
<p>There's no need for joins or heavy normalisation. To get the performance DynamoDB is built for, model your data so it can be retrieved efficiently using keys – partition keys and sort keys – rather than relying on table scans or complex query logic.</p>
<p>If you try to use DynamoDB like SQL, it will fight you — and you will lose.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>There are a few things you'll need and some general knowledge that you should have to follow along most effectively here:</p>
<p><strong>AWS</strong></p>
<ul>
<li><p>An active AWS account with permissions to create and modify DynamoDB</p>
</li>
<li><p>Basic familiarity with the AWS Console (navigating services, not deep expertise)</p>
</li>
</ul>
<p><strong>C# / .NET</strong></p>
<ul>
<li><p>Comfortable with C#</p>
</li>
<li><p>Dependency injection</p>
</li>
<li><p>NuGet package management — you'll need to install <code>AWSSDK.DynamoDBv2</code></p>
</li>
</ul>
<p><strong>Databases (Conceptual)</strong></p>
<ul>
<li>(Optional) A working understanding of relational databases / SQL is actually helpful here — the article explicitly addresses readers coming from that background and explains the mental shift required</li>
</ul>
<p><strong>What you don't need</strong></p>
<ul>
<li><p>Prior DynamoDB experience — the article covers core concepts from scratch</p>
</li>
<li><p>Deep AWS infrastructure knowledge — IAM, VPCs, and so on aren't covered</p>
</li>
</ul>
<p><strong>Optional but useful</strong></p>
<ul>
<li><p>AWS CLI installed locally if you want to follow the AWS CLI examples directly</p>
</li>
<li><p>Terraform experience if following the infrastructure-as-code example (Terraform section can be skipped without losing context)</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ul>
<li><p><a href="#heading-core-dynamodb-concepts">Core DynamoDB Concepts</a></p>
<ul>
<li><p><a href="#heading-partition-key">Partition Key</a></p>
</li>
<li><p><a href="#heading-sort-key-optional">Sort Key (Optional)</a></p>
</li>
<li><p><a href="#heading-global-secondary-index-gsi">Global Secondary Index (GSI)</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-synthetic-keys-the-old-way">Synthetic Keys — The Old Way</a></p>
</li>
<li><p><a href="#heading-multi-attribute-gsis-the-new-way">Multi-Attribute GSIs — The New Way</a></p>
<ul>
<li><p><a href="#heading-defining-a-multi-attribute-gsi">Defining a Multi-Attribute GSI</a></p>
</li>
<li><p><a href="#heading-query-rules-you-must-follow">Query Rules You Must Follow</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-c-sdk-options">C# SDK Options</a></p>
<ul>
<li><p><a href="#heading-low-level-client">Low-Level Client</a></p>
</li>
<li><p><a href="#heading-document-model">Document Model</a></p>
</li>
<li><p><a href="#heading-object-persistence-model">Object Persistence Model</a></p>
</li>
<li><p><a href="#heading-setting-up-the-context">Setting Up the Context</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-querying-a-multi-attribute-gsi-from-c">Querying a Multi-Attribute GSI from C</a></p>
</li>
<li><p><a href="#heading-query-vs-scan">Query vs Scan</a></p>
<ul>
<li><p><a href="#heading-query">Query</a></p>
</li>
<li><p><a href="#heading-scan">Scan</a></p>
</li>
<li><p><a href="#heading-when-is-a-scan-acceptable">When Is A Scan Acceptable?</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-filter-expressions">Filter Expressions</a></p>
</li>
<li><p><a href="#heading-paging-results-and-user-interfaces">Paging Results and User Interfaces</a></p>
<ul>
<li><p><a href="#heading-how-it-works-in-dynamodb">How It Works in DynamoDB</a></p>
</li>
<li><p><a href="#heading-how-this-works-in-the-dynamodb-c-sdk">How This Works In The DynamoDB C# SDK</a></p>
</li>
<li><p><a href="#heading-manual-pagination-the-right-approach-for-uis">Manual Pagination — The Right Approach For UIs</a></p>
</li>
<li><p><a href="#heading-what-about-go-to-to-page-7-navigation">What About "go to to page 7" Navigation?</a></p>
</li>
<li><p><a href="#heading-the-filterexpression-trap">The FilterExpression Trap</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-final-thoughts-amp-conclusion">Final Thoughts &amp; Conclusion</a></p>
</li>
</ul>
<h2 id="heading-core-dynamodb-concepts">Core DynamoDB Concepts</h2>
<p>DynamoDB is built around a few core concepts that directly influence how you query and structure your data.</p>
<p>Remember: DynamoDB is driven by how you retrieve your data, not by the shape of the data itself.</p>
<h3 id="heading-partition-key">Partition Key</h3>
<ul>
<li><p>Required for every query</p>
</li>
<li><p>Required to create a table – each table must have a partition key</p>
</li>
<li><p>Determines data distribution and how items are stored</p>
</li>
</ul>
<p>Data in DynamoDB is physically distributed across partitions. The partition key decides where a given item lives, which is why it's critical for both performance and scalability.</p>
<p>You can think of a partition key like a filing cabinet drawer label: it tells DynamoDB which drawer to open so it can go straight to your data without searching every drawer.</p>
<p>Partition keys are typically strings or numbers.</p>
<h3 id="heading-sort-key-optional">Sort Key (Optional)</h3>
<p>Also known as the <strong>Range Key</strong>.</p>
<ul>
<li>Enables range queries (<code>between</code>, <code>begins_with</code>, and so on)</li>
</ul>
<p>When you add a sort key, items with the same partition key are grouped together and ordered by the sort key. For string sort keys, ordering is lexicographical (dictionary order). For numeric sort keys, ordering is numeric (ascending).</p>
<p>This has an important effect when working with dates. If you store dates as strings in a non-ISO format (for example, <code>DD/MM/YYYY</code>), they won't sort in chronological order. For example, the resulting sorted items would look like this:</p>
<pre><code class="language-plaintext">01/01/2026
01/02/2026
01/03/2026
08/01/2026
15/02/2026
</code></pre>
<p>Here, all dates starting with <code>01</code> are grouped together, even though they span different months. This breaks range queries and ordering.</p>
<p>To avoid this, use either:</p>
<ul>
<li><p><strong>ISO 8601 format</strong> (<code>YYYY-MM-DD</code>), which sorts correctly as a string</p>
</li>
<li><p><strong>Unix timestamps</strong> (typically milliseconds since January 1st, 1970), which sort numerically and correctly</p>
</li>
</ul>
<p>Both approaches ensure your data is ordered correctly and can be queried efficiently. This is commonly used for timestamps, versioning, or logical groupings (for example, <code>ORDER#2024-01</code>).</p>
<h3 id="heading-global-secondary-index-gsi">Global Secondary Index (GSI)</h3>
<p>A Global Secondary Index (GSI) allows you to query your data using a different partition key and optional sort key than your base table. This is how you support additional access patterns without redesigning your primary key schema.</p>
<p>For example, if your base table is keyed by <code>UserId</code>, but you also need to query by <code>OrderId</code>, a GSI makes that possible.</p>
<h4 id="heading-projection-types">Projection Types</h4>
<p>A GSI doesn't have to include all attributes from the base table. When configuring your GSI you can choose:</p>
<ul>
<li><p><strong>ALL</strong> — all attributes are projected</p>
</li>
<li><p><strong>KEYS_ONLY</strong> — only index and primary keys</p>
</li>
<li><p><strong>INCLUDE</strong> — a subset of selected attributes</p>
</li>
</ul>
<p>Choosing the right projection helps reduce storage and read costs. For example, for an orders view you could project only <code>orderNumber</code>, <code>dateOrdered</code>, and <code>cost</code> rather than all other attributes which aren't needed.</p>
<h4 id="heading-important-considerations">Important Considerations</h4>
<p><strong>Additional cost:</strong> GSIs consume their own read/write capacity and storage in addition to your base table's costs. Using <code>ProjectionType = INCLUDE</code> or <code>KEYS_ONLY</code> instead of <code>ALL</code> reduces the storage cost of the GSI since less data is duplicated into the index, which can offset the additional read/write cost.</p>
<p><strong>Eventual consistency:</strong> In DynamoDB, when you write directly to the base table you have the option to perform a strongly consistent read immediately after — meaning you're guaranteed to get the latest data. GSIs don'r support this. GSI reads are always eventually consistent.</p>
<p>When a customer places an order, DynamoDB writes that order to your main Orders table. It then replicates that change to any GSIs asynchronously in the background. During that brief window (typically milliseconds), a query against a GSI may not return the newly written order yet.</p>
<p>A real-world example of where this can catch you out:</p>
<ol>
<li><p>Customer places an order which is written to the Orders table</p>
</li>
<li><p>User is redirected to the "Your Orders" page</p>
</li>
<li><p>"Your Orders" page queries a GSI for all orders by this customer</p>
</li>
<li><p>New order doesn't appear yet — GSI replication is still in progress</p>
</li>
<li><p>Customer refreshes the page 50ms later</p>
</li>
<li><p>Order now appears</p>
</li>
</ol>
<p>For most queries — browsing a product catalogue, viewing order history, filtering by status — this is completely acceptable and unnoticeable to the user. Where it matters is when your application writes a record and immediately queries a GSI for that same record. In this scenario you have a couple of options:</p>
<ul>
<li><p>Query the base table directly after a write using a strongly consistent read, rather than the GSI</p>
</li>
<li><p>Pass the order data directly to the UI from the write response, without a follow-up query at all — the cleanest solution in most cases</p>
</li>
</ul>
<p><strong>Write amplification:</strong> Every write to the base table may also write to one or more GSIs. GSIs are powerful, but they're not free. Overusing them is often a sign that your primary access patterns weren't well defined upfront.</p>
<p><strong>Note:</strong> DynamoDB allows a maximum of 20 GSIs per table by default, though this can be increased via an AWS service limit request.</p>
<h2 id="heading-synthetic-keys-the-old-way">Synthetic Keys — The Old Way</h2>
<p>Before we look at multi-attribute GSIs, it's worth understanding the pattern they replace — because you'll encounter it in existing DynamoDB codebases.</p>
<p>Imagine you want to query orders by both status and date — for example, all "pending" orders placed in the last 30 days. Previously, DynamoDB GSIs only supported a single attribute as the partition key and a single attribute as the sort key. To filter on multiple attributes you had to combine them into a single synthetic attribute:</p>
<pre><code class="language-csharp">[DynamoDBTable("Orders")]
public class OrderDto
{
    [DynamoDBHashKey("customerId")]
    public string CustomerId { get; set; }

    [DynamoDBRangeKey("createdAt")]
    public long CreatedAt { get; set; }

    [DynamoDBProperty("orderId")]
    public string OrderId { get; set; }

    [DynamoDBProperty("status")]
    public string Status { get; set; }

    // Synthetic key — manually constructed before saving
    [DynamoDBProperty("statusDate")]
    public string StatusDate { get; set; } // e.g. "PENDING#2025-11-01"
}
</code></pre>
<p>Constructing this value before saving the record:</p>
<pre><code class="language-csharp">order.StatusDate = $"{order.Status}#{order.CreatedAt:yyyy-MM-dd}";
</code></pre>
<p>Then create a GSI on <code>statusDate</code> as the partition key, allowing you to query:</p>
<pre><code class="language-csharp">var results = await _context.QueryAsync&lt;OrderDto&gt;(
    "PENDING#2025-11-01",
    config // IndexName = "statusDate-index"
).GetRemainingAsync();
</code></pre>
<p>This worked, but came with real downsides:</p>
<ul>
<li><p><strong>Brittle</strong> — every developer writing to the table must know about and correctly format the synthetic key</p>
</li>
<li><p><strong>Hard to query ranges</strong> — filtering all pending orders across a date range required careful <code>begins_with</code> or <code>between</code> conditions on a concatenated string</p>
</li>
<li><p><strong>Maintenance overhead</strong> — if status values change, every existing record needs updating</p>
</li>
<li><p><strong>Invisible in the schema</strong> — a new developer has no idea what <code>statusDate</code> means without documentation</p>
</li>
<li><p><strong>Backfilling</strong> — adding a new synthetic-key GSI to an existing table meant updating every existing record to populate the new attribute via a script re-processing the existing items.</p>
</li>
</ul>
<h2 id="heading-multi-attribute-gsis-the-new-way">Multi-Attribute GSIs — The New Way</h2>
<p>On November 19, 2025, AWS <a href="https://aws.amazon.com/about-aws/whats-new/2025/11/amazon-dynamodb-multi-attribute-composite-keys-global-secondary-indexes/">announced multi-attribute composite keys for GSIs</a>. You can now define a GSI partition key or sort key comprised of up to <strong>4 attributes each</strong> — <strong>8 attributes in total</strong> across the partition and sort key combined.</p>
<p>A few important things to note:</p>
<ul>
<li><p><strong>GSIs only:</strong> This applies to GSIs only — your base table primary key structure is unchanged, still a single partition key and an optional single sort key.</p>
</li>
<li><p><strong>DynamoDB handles composition internally:</strong> You don't concatenate values yourself. DynamoDB hashes the partition key attributes together for data distribution, and maintains hierarchical sort order across the sort key attributes.</p>
</li>
<li><p><strong>Strict query rules still apply:</strong> You must supply <strong>all</strong> partition key attributes with equality conditions when querying. Sort key attributes must be queried <strong>left-to-right</strong> in the order they were defined — you can't skip attributes.</p>
</li>
<li><p><strong>No backfilling required.</strong> When you add a multi-attribute GSI to an existing table, DynamoDB automatically indexes all existing items using their natural attributes.</p>
</li>
<li><p><strong>No additional cost</strong> beyond standard GSI pricing.</p>
</li>
</ul>
<p>The model stays clean — no synthetic attributes needed:</p>
<pre><code class="language-csharp">[DynamoDBTable("Orders")]
public class OrderDto
{
    [DynamoDBHashKey("customerId")]
    public string CustomerId { get; set; }

    [DynamoDBRangeKey("createdAt")]
    public long CreatedAt { get; set; }

    [DynamoDBProperty("orderId")]
    public string OrderId { get; set; }

    [DynamoDBProperty("status")]
    public string Status { get; set; }

    [DynamoDBProperty("total")]
    public decimal Total { get; set; }
}
</code></pre>
<h3 id="heading-defining-a-multi-attribute-gsi">Defining a Multi-Attribute GSI</h3>
<p>You can create the GSI via the AWS Console (select the attributes you want in order), via Terraform (requires AWS provider v6.29.0+), or via the AWS CLI.</p>
<p>The key concept to understand: you provide <strong>multiple</strong> <code>HASH</code> <strong>entries</strong> for the composite partition key and <strong>multiple</strong> <code>RANGE</code> <strong>entries</strong> for the composite sort key, in the exact order they should be evaluated. DynamoDB treats them internally as one composite partition key and one composite sort key.</p>
<p>Here's an AWS CLI example — a GSI on Orders with a composite partition key (<code>customerId</code> + <code>status</code>) and a single-attribute sort key (<code>createdAt</code>):</p>
<pre><code class="language-bash">aws dynamodb update-table \
  --table-name Orders \
  --attribute-definitions \
    AttributeName=customerId,AttributeType=S \
    AttributeName=status,AttributeType=S \
    AttributeName=createdAt,AttributeType=N \
  --global-secondary-index-updates \
  "[{\"Create\":{
    \"IndexName\":\"customerStatus-createdAt-index\",
    \"KeySchema\":[
      {\"AttributeName\":\"customerId\",\"KeyType\":\"HASH\"},
      {\"AttributeName\":\"status\",\"KeyType\":\"HASH\"},
      {\"AttributeName\":\"createdAt\",\"KeyType\":\"RANGE\"}
    ],
    \"Projection\":{\"ProjectionType\":\"ALL\"}
  }}]"
</code></pre>
<p>The two <code>HASH</code> entries here are valid. They define a composite partition key of <code>(customerId, status)</code>. This is the syntax AWS introduced specifically for multi-attribute GSIs. It would have been rejected before November 2025.</p>
<p>Here's a Terraform example (AWS provider v6.29.0+):</p>
<pre><code class="language-hcl">global_secondary_index {
  name            = "customerStatus-createdAt-index"
  projection_type = "ALL"

  key_schema {
    attribute_name = "customerId"
    key_type       = "HASH"
  }

  key_schema {
    attribute_name = "status"
    key_type       = "HASH"
  }

  key_schema {
    attribute_name = "createdAt"
    key_type       = "RANGE"
  }
}
</code></pre>
<h3 id="heading-query-rules-you-must-follow">Query Rules You Must Follow</h3>
<p>The flexibility gain with multi-attribute GSIs is real, but the query constraints are not the same as SQL. Two rules matter most:</p>
<h4 id="heading-1-partition-key-attributes-must-all-be-supplied-with-equality-only">1. Partition key attributes must all be supplied, with equality only.</h4>
<p>For a partition key of <code>(customerId, status)</code>:</p>
<p><strong>Valid</strong>:</p>
<pre><code class="language-plaintext">customerId = 'C123' AND status = 'PENDING'
</code></pre>
<p><strong>Invalid</strong> — missing <code>status</code>:</p>
<pre><code class="language-plaintext">customerId = 'C123'
</code></pre>
<p><strong>Invalid</strong> — inequality on a partition key attribute:</p>
<pre><code class="language-plaintext">customerId = 'C123' AND status &gt; 'P'
</code></pre>
<h4 id="heading-2-sort-key-attributes-must-be-queried-left-to-right-with-inequality-only-as-the-final-condition">2. Sort key attributes must be queried left-to-right, with inequality only as the final condition.</h4>
<p>For a sort key of <code>(tournamentRound, rank, matchId)</code>:</p>
<p><strong>Valid</strong>:</p>
<pre><code class="language-plaintext">tournamentRound = 'SEMIFINALS'

tournamentRound = 'SEMIFINALS' AND rank = 'UPPER'

tournamentRound = 'SEMIFINALS' AND rank = 'UPPER' AND matchId = 'match-002'

tournamentRound = 'SEMIFINALS' AND rank = 'UPPER' AND matchId &gt; 'match-001'

tournamentRound BETWEEN 'QUARTERFINALS' AND 'SEMIFINALS'
</code></pre>
<p><strong>Invalid</strong> — skipping the first attribute:</p>
<pre><code class="language-plaintext">rank = 'UPPER'
</code></pre>
<p><strong>Invalid</strong> — leaving a gap (skipping <code>bracket</code>)</p>
<pre><code class="language-plaintext">tournamentRound = 'SEMIFINALS' AND matchId = 'match-002'
</code></pre>
<p><strong>Invalid</strong> — adding a condition after an inequality:</p>
<pre><code class="language-plaintext">tournamentRound &gt; 'QUARTERFINALS' AND rank = 'UPPER'
</code></pre>
<p><strong>Design tip:</strong> Order your sort key attributes from most general to most specific for example, <code>tournamentRound → rank → matchId</code>). This maximises query flexibility, since each left-to-right prefix becomes a valid query pattern.</p>
<h4 id="heading-going-deeper">Going deeper:</h4>
<p>AWS publishes a detailed design pattern guide with worked examples for time-series data, e-commerce orders, hierarchical organisation data, and multi-tenant SaaS platforms. The examples use the JavaScript SDK, but the schema design principles apply regardless of language. The article can be found <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.DesignPattern.MultiAttributeKeys.html">here</a>.</p>
<h2 id="heading-c-sdk-options">C# SDK Options</h2>
<p>When working with DynamoDB in C#, the <code>AWSSDK.DynamoDBv2</code> NuGet package gives you three different ways to interact with your tables, each with different levels of abstraction.</p>
<h3 id="heading-low-level-client">Low-Level Client</h3>
<pre><code class="language-csharp">var client = new AmazonDynamoDBClient();
</code></pre>
<p>The <code>AmazonDynamoDBClient</code> gives you full control over every aspect of your DynamoDB interactions. You construct requests manually, specifying every attribute, condition, and configuration explicitly.</p>
<pre><code class="language-csharp">var request = new QueryRequest
{
    TableName = "Orders",
    KeyConditionExpression = "customerId = :customerId",
    ExpressionAttributeValues = new Dictionary&lt;string, AttributeValue&gt;
    {
        { ":customerId", new AttributeValue { S = "customer-123" } }
    }
};

var response = await client.QueryAsync(request);
</code></pre>
<p>This is the most verbose approach, but nothing is hidden from you. You can see exactly what's being sent to DynamoDB, which makes it easier to debug, optimise, and understand exactly what Read Capacity Units (RCUs) you're consuming. It's also the most flexible — anything DynamoDB supports, you can do here.</p>
<p><strong>When to use it:</strong><br>When you need fine-grained control, are doing something complex, or want full visibility into your queries.</p>
<h3 id="heading-document-model">Document Model</h3>
<pre><code class="language-csharp">var client = new AmazonDynamoDBClient();
var table = Table.LoadTable(client, "Orders");
</code></pre>
<p>The Document Model sits a level above the low-level client. Rather than working with raw <code>AttributeValue</code> types, you work with <code>Document</code> objects which feel more like JSON — familiar to most .NET developers.</p>
<pre><code class="language-csharp">var filter = new QueryFilter("customerId", QueryOperator.Equal, "customer-123");
var search = table.Query(filter);
var documents = await search.GetRemainingAsync();

// access the data
foreach (var doc in documents)
{
    Console.WriteLine(doc["orderId"].AsString());
    Console.WriteLine(doc["total"].AsDecimal());
}
</code></pre>
<p>Less boilerplate than the low-level client, but you're still working with loosely typed <code>Document</code> objects rather than your own C# classes. There's no mapping to strongly typed models out of the box.</p>
<p><strong>When to use it:</strong><br>Useful for dynamic or loosely structured data where you don't want to define a fixed model, or for quick tooling and scripts.</p>
<h3 id="heading-object-persistence-model">Object Persistence Model</h3>
<p>The Object Persistence Model is the highest level of abstraction and the most natural fit for typical .NET development.</p>
<p>You decorate your C# classes with attributes, and the <code>DynamoDBContext</code> handles serialisation and deserialisation automatically — similar to an ORM like Entity Framework.</p>
<pre><code class="language-csharp">[DynamoDBTable("Orders")]
public class OrderRecord
{
    [DynamoDBHashKey("customerId")]
    public string CustomerId { get; set; }

    [DynamoDBRangeKey("createdAt")]
    public long CreatedAt { get; set; }

    [DynamoDBProperty("orderId")]
    public string OrderId { get; set; }

    [DynamoDBProperty("total")]
    public decimal Total { get; set; }

    [DynamoDBProperty("status")]
    public string Status { get; set; }
}
</code></pre>
<p>Querying feels clean and strongly typed:</p>
<pre><code class="language-csharp">var orders = await dbContext
    .QueryAsync&lt;OrderRecord&gt;("customer-123")
    .GetRemainingAsync();
</code></pre>
<p>The trade-off is that the abstraction hides some important details: you don't always see exactly what's being sent to DynamoDB under the hood, which can make debugging and performance optimisation harder.</p>
<h3 id="heading-setting-up-the-context">Setting Up the Context</h3>
<p>When creating the db context there are a couple of options:</p>
<h4 id="heading-option-1-using-dependency-injection">Option 1 — using Dependency Injection:</h4>
<pre><code class="language-csharp">// Program.cs
builder.Services.AddSingleton&lt;IAmazonDynamoDB, AmazonDynamoDBClient&gt;();

builder.Services.AddSingleton&lt;IDynamoDBContext&gt;(sp =&gt;
{
    var client = sp.GetRequiredService&lt;IAmazonDynamoDB&gt;();
    return new DynamoDBContext(client);
});

// Then in repository / service, inject IDynamoDBContext
public class OrderRepository
{
    private readonly IDynamoDBContext _context;

    public OrderRepository(IDynamoDBContext context)
    {
        _context = context;
    }
}
</code></pre>
<h4 id="heading-option-2-register-amazondynamodbclient-only-and-instantiate-the-context-per-operation">Option 2 — register <code>AmazonDynamoDBClient</code> only, and instantiate the context per operation:</h4>
<pre><code class="language-csharp">// Program.cs
builder.Services.AddSingleton&lt;IAmazonDynamoDB, AmazonDynamoDBClient&gt;();
</code></pre>
<p>Then:</p>
<pre><code class="language-csharp">public class OrderRepository
{
    private readonly IAmazonDynamoDB _client;

    public OrderRepository(IAmazonDynamoDB client)
    {
        _client = client;
    }

    public async Task&lt;List&lt;OrderDto&gt;&gt; GetOrdersAsync(string customerId)
    {
        var context = new DynamoDBContext(_client); // lightweight to instantiate
        return await context.QueryAsync&lt;OrderDto&gt;(customerId).GetRemainingAsync();
    }
}
</code></pre>
<p><strong>Which is better?</strong> Option 1 is cleaner and more testable — you can mock <code>IDynamoDBContext</code> in unit tests easily. Option 2 is also valid since <code>DynamoDBContext</code> is lightweight to instantiate, but you lose the ability to mock it cleanly.</p>
<p><strong>When to use Object Persistence:</strong> the recommended approach for most .NET applications. Clean, strongly typed, and fits naturally into existing C# codebases.</p>
<h2 id="heading-querying-a-multi-attribute-gsi-from-c">Querying a Multi-Attribute GSI From C#</h2>
<p>At the time of writing, the <code>DynamoDBContext.QueryAsync&lt;T&gt;</code> convenience overloads don't support multi-attribute GSI key conditions directly — you need to use the low-level client (<code>IAmazonDynamoDB</code>) and pass a <code>KeyConditionExpression</code>. The good news is the deserialisation back to your typed model is still straightforward.</p>
<p>Here's a query against a GSI with a composite partition key of <code>(customerId, status)</code> and a sort key of <code>createdAt</code>, returning all pending orders for a customer since a given date:</p>
<pre><code class="language-csharp">public async Task&lt;List&lt;OrderDto&gt;&gt; GetOrdersByStatusSinceAsync(
    string customerId,
    string status,
    long fromDate)
{
    var request = new QueryRequest
    {
        TableName = "Orders",
        IndexName = "customerStatus-createdAt-index",
        KeyConditionExpression =
            "customerId = :customerId " +
            "AND #status = :status " +           // #status because 'status' is a reserved word
            "AND createdAt &gt; :fromDate",
        ExpressionAttributeNames = new Dictionary&lt;string, string&gt;
        {
            { "#status", "status" }
        },
        ExpressionAttributeValues = new Dictionary&lt;string, AttributeValue&gt;
        {
            { ":customerId", new AttributeValue { S = customerId } },
            { ":status",     new AttributeValue { S = status } },
            { ":fromDate",   new AttributeValue { N = fromDate.ToString() } }
        },
        ScanIndexForward = false // reverse sort key order — newest first, since sort key is a timestamp
    };

    var response = await _client.QueryAsync(request);

    // manually deserialise back to OrderDto using the DynamoDBContext
    return _context.FromDocuments&lt;OrderDto&gt;(
        response.Items.Select(Document.FromAttributeMap)
    ).ToList();
}
</code></pre>
<p>Looking at the code above, notice that:</p>
<ul>
<li><p>Both partition key attributes (<code>customerId</code> and <code>status</code>) are supplied with equality — this is required.</p>
</li>
<li><p>The sort key (<code>createdAt</code>) uses an inequality <code>&gt;</code> (greater than) as the final condition, which is allowed.</p>
</li>
<li><p>No synthetic string construction, no brittle formatting conventions, no backfilling existing records.</p>
</li>
</ul>
<p>If you're working on an existing codebase that uses synthetic keys, it's worth evaluating whether migrating to multi-attribute GSIs makes sense. The backfilling problem that made migrations painful before is gone, DynamoDb multi-attribute GSIs handle it automatically.</p>
<h2 id="heading-query-vs-scan">Query vs Scan</h2>
<p>This is one of the most important concepts to understand when working with DynamoDB — and one of the most common sources of performance and cost problems.</p>
<h3 id="heading-query">Query</h3>
<p>A <code>Query</code> retrieves items using the partition key, and optionally narrows results using the sort key. DynamoDB knows exactly which partition to look in, reads only the relevant items, and returns them efficiently.</p>
<pre><code class="language-csharp">// Get all orders for a customer
var orders = await _context
    .QueryAsync&lt;OrderDto&gt;("customer-123")
    .GetRemainingAsync();
</code></pre>
<p>You can narrow further using a sort key condition — for example, all orders placed in the last 30 days:</p>
<pre><code class="language-csharp">var thirtyDaysAgo = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();

var orders = await _context.QueryAsync&lt;OrderDto&gt;(
    "customer-123",
    QueryOperator.GreaterThan,
    new List&lt;object&gt; { thirtyDaysAgo }
).GetRemainingAsync();
</code></pre>
<p>Queries are fast and cheap — you only pay RCUs for the records actually read.</p>
<h3 id="heading-scan">Scan</h3>
<p>A <code>Scan</code> reads every single item in the table, then filters the results. It doesn't use keys or indexes — it brute-forces through everything.</p>
<pre><code class="language-csharp">var conditions = new List&lt;ScanCondition&gt;
{
    new ScanCondition("status", ScanOperator.Equal, "pending")
};

var orders = await _context
    .ScanAsync&lt;OrderDto&gt;(conditions)
    .GetRemainingAsync();
</code></pre>
<p>This works — but on a table with 10 million orders, DynamoDB reads all 10 million records and then filters down to the pending ones. You pay RCUs for every single record read, not just the ones returned.</p>
<p><strong>Important:</strong> Scans should be avoided in production for large tables. They're slow, expensive, and get worse as your table grows.</p>
<p>The difference visualised:</p>
<pre><code class="language-plaintext">Query:
Table [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■]
       └── Jump straight to partition "customer-123"
               └── Read only these items — cheap

Scan:
Table [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■]
       └── Read every single item — expensive
               └── Then discard non-matching items
</code></pre>
<h3 id="heading-when-is-a-scan-acceptable">When Is A Scan Acceptable?</h3>
<p>Scans aren't always wrong — there are legitimate use cases:</p>
<ul>
<li><p><strong>Small tables</strong> — a lookup table with 50 items, a scan is perfectly fine</p>
</li>
<li><p><strong>One-off data migrations or admin scripts</strong> — not user-facing, run occasionally</p>
</li>
<li><p><strong>Development and debugging</strong> — scanning locally or against a small dataset</p>
</li>
</ul>
<p><strong>Rule of thumb:</strong> if it's a user-facing query on a growing table, it should be a Query, not a Scan.</p>
<p>Coming from SQL, developers often reach for a Scan because it feels like:</p>
<pre><code class="language-sql">SELECT * FROM orders WHERE status = 'pending'
</code></pre>
<p>In SQL with a good index, that's fine. In DynamoDB, without a GSI on <code>status</code>, that's a full table scan every time. The solution is to design a GSI for the access patterns you need — exactly what we covered in the GSI section earlier.</p>
<h2 id="heading-filter-expressions">Filter Expressions</h2>
<p>Both Query and Scan support an optional <code>FilterExpression</code> — a condition applied <em>after</em> DynamoDB has read the records but <em>before</em> they're returned to you. It looks superficially like a SQL <code>WHERE</code> clause, and that's exactly the trap.</p>
<pre><code class="language-csharp">var request = new QueryRequest
{
    TableName = "Orders",
    KeyConditionExpression = "customerId = :customerId",
    FilterExpression = "#status = :status",
    ExpressionAttributeNames = new Dictionary&lt;string, string&gt;
    {
        { "#status", "status" }
    },
    ExpressionAttributeValues = new Dictionary&lt;string, AttributeValue&gt;
    {
        { ":customerId", new AttributeValue { S = "customer-123" } },
        { ":status",     new AttributeValue { S = "pending" } }
    }
};
</code></pre>
<p>The critical thing to understand: <code>FilterExpression</code> does <strong>not</strong> reduce the cost of the query. DynamoDB still reads every record first, charges you RCUs for all of them, and only then discards the ones that don't match the filter.</p>
<p>For a Query, that means every record matched by the <code>KeyConditionExpression</code>. For a Scan, that means every record in the table.</p>
<p>It's a convenience for trimming the <em>response payload</em>, not a tool for efficient querying. If you find yourself reaching for <code>FilterExpression</code> to support a real access pattern, that's a signal you need a GSI instead.</p>
<h2 id="heading-paging-results-and-user-interfaces">Paging Results and User Interfaces</h2>
<p>Pagination is one of the most misunderstood aspects of DynamoDB, especially if you're coming from a SQL background.</p>
<p>In SQL you might write:</p>
<pre><code class="language-sql">SELECT * FROM orders LIMIT 10 OFFSET 20
</code></pre>
<p>DynamoDB doesn't work like this. There is no concept of <code>OFFSET</code> or page numbers. Instead, DynamoDB uses cursor-based pagination via a <code>LastEvaluatedKey</code>.</p>
<h3 id="heading-how-it-works-in-dynamodb">How It Works In DynamoDB</h3>
<p>DynamoDB returns a maximum of 1MB of data per request. If your results exceed 1MB, DynamoDB returns a <code>LastEvaluatedKey</code> — a pointer to where it stopped reading. Pass this back in to the next request to continue from that position. When no <code>LastEvaluatedKey</code> is returned, you've reached the end of the data.</p>
<h3 id="heading-how-this-works-in-the-dynamodb-c-sdk">How This Works In The DynamoDB C# SDK</h3>
<p>The SDK's <code>GetRemainingAsync()</code> method handles pagination automatically, it keeps making requests until there is no <code>LastEvaluatedKey</code> left, returning everything as a single list:</p>
<pre><code class="language-csharp">// Handles all pages automatically — but loads everything into memory
var orders = await _context
    .QueryAsync&lt;OrderDto&gt;("customer-123")
    .GetRemainingAsync();
</code></pre>
<p>This is convenient but dangerous on large datasets. If a customer has 50,000 orders, you're loading all 50,000 into memory in one go.</p>
<h3 id="heading-manual-pagination-the-right-approach-for-uis">Manual Pagination — The Right Approach For UIs</h3>
<p>For a UI with "load more" or "next/previous" navigation, control pagination manually using <code>GetNextSetAsync()</code>:</p>
<pre><code class="language-csharp">// ---- Paging Model ----
public class PagedResult&lt;T&gt;
{
    public List&lt;T&gt; Items { get; set; }
    public string? PaginationToken { get; set; }
}

// ---- Repository Method ----
public async Task&lt;PagedResult&lt;OrderDto&gt;&gt; GetOrdersPageAsync(
    string customerId,
    string? paginationToken = null)
{
    var config = new DynamoDBOperationConfig
    {
        BackwardQuery = true // reverse sort key order — newest first if sort key is a timestamp
    };

    var search = _context.QueryAsync&lt;OrderDto&gt;(customerId, config);

    if (paginationToken != null)
        search.PaginationToken = paginationToken;

    var items = await search.GetNextSetAsync(25); // fetch exactly 25 records

    return new PagedResult&lt;OrderDto&gt;
    {
        Items = items,
        PaginationToken = search.PaginationToken // null if no more pages
    };
}
</code></pre>
<p>The <code>PaginationToken</code> is the SDK's serialised representation of the <code>LastEvaluatedKey</code> — pass it directly to the client as a string and receive it back on the next request.</p>
<h3 id="heading-what-about-go-to-to-page-7-navigation">What About "go to to page 7" Navigation?</h3>
<p>This isn't possible in DynamoDB. The <code>LastEvaluatedKey</code> is a position cursor, to reach page 7 you'd have to paginate through pages 1 to 6 first to obtain the correct cursor placement.</p>
<p>For most modern UIs this isn't a problem. Infinite scroll and "load more" patterns map naturally to cursor-based pagination.</p>
<h3 id="heading-the-filterexpression-trap">The <code>FilterExpression</code> Trap</h3>
<p>We've already seen that <code>FilterExpression</code> is a poor substitute for a well-designed GSI. Pagination is where it goes from "wasteful" to actively broken.</p>
<p>DynamoDB's pagination works in two stages when a <code>FilterExpression</code> is involved:</p>
<ol>
<li><p>Read records until the 1MB limit is reached</p>
</li>
<li><p>Apply the <code>FilterExpression</code>, discarding non-matching records</p>
</li>
</ol>
<p>The <code>LastEvaluatedKey</code> is generated <strong>after step 1 — before filtering</strong>. So DynamoDB can return a <code>LastEvaluatedKey</code> implying there are more results, even if the filtered page returned only a handful of records.</p>
<p>With 1,000 orders where only 50 are "pending":</p>
<pre><code class="language-plaintext">Page 1: Read 200 records → filter applied → 3 "pending" returned + LastEvaluatedKey

Page 2: Read 200 records → filter applied → 1 "pending" returned + LastEvaluatedKey

Page 3: Read 200 records → filter applied → 0 "pending" returned + LastEvaluatedKey

...and so on until all 1,000 records are read
</code></pre>
<p><strong>Important:</strong> You pay RCUs for every record <strong>read</strong>, NOT every record <strong>returned</strong>.</p>
<p>The <code>Limit</code> parameter doesn't rescue you here. <code>GetNextSetAsync(25)</code> caps the records <em>read</em> before filtering, not the records <em>returned</em>. You can read 25, filter down to 3, and still get a <code>LastEvaluatedKey</code> back, meaning your "page size of 25" actually returns somewhere between 0 and 25 results, unpredictably.</p>
<p>The real fix isn't a smarter pagination strategy, it's removing the <code>FilterExpression</code> entirely. Design a GSI keyed on the attribute you're filtering by (here, <code>status</code>, or a multi-attribute GSI with <code>status</code> in the partition key). DynamoDB then reads only the matching records directly, <code>Limit</code> caps what you actually want, and pagination behaves predictably.</p>
<h2 id="heading-final-thoughts-amp-conclusion">Final Thoughts &amp; Conclusion</h2>
<p>DynamoDB rewards you for designing around your access patterns up front, and punishes you for pretending it's SQL. The two biggest shifts from a relational mindset are:</p>
<ol>
<li><p><strong>Queries are the schema.</strong> You model tables, keys, and GSIs around the queries you need to run. You don't normalise and figure out queries later.</p>
</li>
<li><p><strong>Keys do the work.</strong> The Query operation is fast and cheap precisely because it uses the partition key to jump straight to the right data. Scans read everything, and they get worse as your data grows.</p>
</li>
</ol>
<p>The November 2025 multi-attribute GSI release is a genuinely welcome change, and is a huge improvement to the AWS resource. It removes one of the most painful ergonomic issues with DynamoDB, synthetic key construction and backfilling, without loosening the constraints that make DynamoDB fast.</p>
<p>The query rules (all partition-key attributes supplied, sort-key attributes queried left-to-right) stay exactly the same. What you gain is cleaner, typed, natural data models and the ability to add new access patterns to existing tables without a data migration.</p>
<p>For new projects, my recommendation is to use multi-attribute GSIs by default. For existing codebases built on synthetic keys, evaluate whether a migration makes sense, the painful part of such migrations is now gone.</p>
<p>As always if you want to discuss this further, or hear about my other articles drop me a follow on <a href="https://x.com/grantdotdev">'X'</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Work With Dapper in .Net ]]>
                </title>
                <description>
                    <![CDATA[ When you're working with .NET, interacting with databases (particularly SQL databases) is inevitable. Common approaches involve using ORM (Object Relational Mapping) with tools like Entity Framework.  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-work-with-dapper-in-net/</link>
                <guid isPermaLink="false">69c46b2610e664c5da070aa0</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Wed, 25 Mar 2026 23:09:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/66b52b176a1b17f6b28d9822/d091bd67-ef80-4cae-ad84-3dc5b79ca73b.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're working with .NET, interacting with databases (particularly SQL databases) is inevitable. Common approaches involve using ORM (Object Relational Mapping) with tools like Entity Framework.</p>
<p>Dapper stands out as a lightweight and high-performance ORM tool with numerous advantages. But where Dapper really excels is in its speed and control. Here, we'll explore Dapper's suitability for performance-critical .NET projects with simpler database relationships utilising raw SQL queries.</p>
<p>The article guides you in building a lightweight .NET Web API for a social media application with Dapper using a Postgres database.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p>Latest .Net SDK and runtime (at time of writing, it's .Net 10).</p>
</li>
<li><p>Knowledge of the C# programming language and how Dependency Injection works</p>
</li>
<li><p>A running PostgreSQL instance</p>
</li>
<li><p>DB Viewer software, for example DBeaver, pgAdmin, or the PostgreSQL extension for VS Code</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-what-is-dapper">What Is Dapper?</a></p>
</li>
<li><p><a href="#heading-challenges-and-advantages-of-dapper">Challenges and Advantages of Dapper</a></p>
</li>
<li><p><a href="#heading-getting-started-installation">Getting Started – Installation</a></p>
</li>
<li><p><a href="#heading-querying-data-with-dapper">Querying Data With Dapper</a></p>
</li>
<li><p><a href="#heading-querysingle-vs-queryfirst">QuerySingle vs QueryFirst</a></p>
</li>
<li><p><a href="#heading-writing-data-with-dapper">Writing Data With Dapper</a></p>
</li>
<li><p><a href="#heading-updating-data-with-dapper">Updating Data With Dapper</a></p>
</li>
<li><p><a href="#heading-deleting-records-with-dapper">Deleting Records With Dapper</a></p>
</li>
<li><p><a href="#heading-batch-processing-with-dapper">Batch Processing With Dapper</a></p>
</li>
<li><p><a href="#heading-transactions-with-dapper">Transactions With Dapper</a></p>
</li>
<li><p><a href="#heading-multi-mapping-splits">Multi-mapping / Splits</a></p>
</li>
<li><p><a href="#heading-what-comes-next-possible-additions">What Comes Next – Possible Additions</a></p>
</li>
<li><p><a href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ul>
<h2 id="heading-what-is-dapper">What Is Dapper?</h2>
<p>Dapper is a "micro ORM", providing lightweight, high-performance data access with minimal abstraction. It relies on SQL queries (these are the queries you use when interacting with an SQL database) for example:</p>
<p><code>SELECT * FROM influencers WHERE ID = 1</code>, mapping the results to objects directly.</p>
<p>Here's how Dapper's README describes what it does:</p>
<blockquote>
<p>This [Dapper] provides a simple and efficient API for invoking SQL, with support for both synchronous and asynchronous data access, and allows both buffered and non-buffered queries. –&nbsp;Dapper github repository README</p>
</blockquote>
<p>An ORM (Object-Relational Mapper) is like a translator between a programming language and a database, allowing software to interact with databases using familiar programming objects (instead of direct SQL queries), making it easier to manage and manipulate data in applications.</p>
<p>As Dapper is a "Micro-ORM", it acts a middle-ground between direct SQL and a full fledged ORM like that of the&nbsp;Entity Framework (EF) which you may have heard of before. It has a lot of the basic features, but doesn't come with all the "bloat," making it a secure and faster database tool.</p>
<h2 id="heading-challenges-and-advantages-of-dapper">Challenges and Advantages of Dapper</h2>
<h3 id="heading-challenges-of-dapper">Challenges of Dapper</h3>
<table>
<thead>
<tr>
<th><strong>Challenge</strong></th>
<th><strong>Description</strong></th>
</tr>
</thead>
<tbody><tr>
<td>No Built-in LINQ Support</td>
<td>Dapper lacks native LINQ integration, forcing developers to write raw SQL instead of using expressive LINQ queries for data filtering and projections. This can slow development for teams accustomed to LINQ in ORMs like EF Core.</td>
</tr>
<tr>
<td>Limited Conventions</td>
<td>With fewer defaults and automations, Dapper requires explicit mappings and configurations for schemas or parameters, leading to more setup code compared to convention-heavy ORMs.</td>
</tr>
<tr>
<td>Fewer Features for Complex Data Models</td>
<td>Handling intricate entity relationships (for example, deep hierarchies or many-to-many joins) demands custom SQL and manual mapping, increasing complexity in apps with rich relational data.</td>
</tr>
<tr>
<td>No Lazy Loading</td>
<td>Related entities aren't loaded on-demand – everything must be eagerly fetched via multi-mapping or separate queries, potentially causing performance issues or extra code for deferred loading.</td>
</tr>
<tr>
<td>Manual SQL Writing</td>
<td>Developers must craft all queries by hand, which can introduce errors, SQL injection risks (if parameters are mishandled), and more boilerplate, making maintenance tougher than auto-generated queries in full ORMs.</td>
</tr>
<tr>
<td>No Change Tracking</td>
<td>Dapper doesn't monitor object changes, so updates and deletes require manual SQL, which can complicate write operations and lead to inefficiencies in CRUD-heavy apps.</td>
</tr>
<tr>
<td>Lack of Database Migrations</td>
<td>No built-in tools for schema evolution or versioning, forcing reliance on external libraries or manual scripts – a stark contrast to EF Core's integrated migrations.</td>
</tr>
<tr>
<td>Connection Management Challenges</td>
<td>While Dapper uses ADO.NET connections, improper handling (for example, not disposing properly) can lead to pooling issues or leaks, especially in high-concurrency web apps.</td>
</tr>
</tbody></table>
<h3 id="heading-advantages-of-dapper">Advantages of Dapper</h3>
<p>But let’s not dwell on the negatives. Now let's concentrate on the advantages, as these far outweigh the challenges.</p>
<table>
<thead>
<tr>
<th>Advantage</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td>Minimal Abstraction</td>
<td>As a micro-ORM, Dapper offers a thin wrapper over ADO.NET, giving developers direct access to SQL without heavy abstractions. This is ideal for those who want precise control over data access code and prefer working closer to the barebones.</td>
</tr>
<tr>
<td>Optimised for Read-Heavy Workloads</td>
<td>Dapper shines in applications with frequent reads, allowing custom SQL optimisations for queries like reporting or dashboards, resulting in faster data retrieval compared to feature-rich ORMs.</td>
</tr>
<tr>
<td>High Performance</td>
<td>Known for its lightweight design and low overhead, Dapper delivers extremely fast execution, especially with large datasets or high-throughput operations. It often outperforms Entity Framework in benchmarks for raw speed.</td>
</tr>
<tr>
<td>Full Control Over SQL Queries</td>
<td>Developers write explicit SQL, enabling fine-tuned queries for complex scenarios; while this requires manual management, it avoids the "black box" issues of auto-generated SQL in other ORMs.</td>
</tr>
<tr>
<td>Flexible Result Mapping</td>
<td>Dapper allows easy mapping of query results to custom objects or view models with custom logic, supporting features like multi-mapping for joins without rigid conventions.</td>
</tr>
<tr>
<td>Simplicity and Ease of Use</td>
<td>With a small API surface and quick setup, Dapper has a low learning curve, making it accessible for rapid prototyping or integrating into existing .NET projects without bloat.</td>
</tr>
<tr>
<td>Support for Multiple Result Sets</td>
<td>Using methods like QueryMultiple, Dapper efficiently handles queries returning several result sets in one call, reducing roundtrips to the database and boosting efficiency.</td>
</tr>
<tr>
<td>Built-in SQL Injection Protection</td>
<td>Automatic parameterisation secures queries against injection attacks, combining raw SQL flexibility with safety out of the box.</td>
</tr>
<tr>
<td>Broad Database Compatibility</td>
<td>Built on ADO.NET, Dapper works seamlessly with any database provider (for example, SQL Server, PostgreSQL), offering versatility without vendor lock-in.</td>
</tr>
</tbody></table>
<h2 id="heading-getting-started-installation">Getting Started – Installation</h2>
<p>You’re going to use the CLI (Command Line Interface) to install Dapper in your project. I've chosen this method, as it’s not only quicker, but will help build confidence with the CLI.</p>
<h3 id="heading-cloning-the-repo">Cloning the Repo:</h3>
<p>In your terminal app, navigate to the folder where you want the repository to be located and run the following command to clone the public tutorial repository:</p>
<pre><code class="language-bash">git clone https://github.com/grant-dot-dev/dapper_tutorial.git
</code></pre>
<p>You then need to add Dapper and the Postgres support to your project. You can do this with the following command:</p>
<pre><code class="language-bash">cd FCC.DapperTutorial

# add Dapper nuget package
dotnet add package Dapper

# add Postgres driver
dotnet add package Npgsql
</code></pre>
<p>Update your <code>defaultConnection</code> connection string within <code>appsettings.json</code> with the location of your <code>Postgres</code> instance.</p>
<pre><code class="language-json">"ConnectionStrings": {
  "DefaultConnection": "Host=localhost;Port=5432;Database=social_media;Username=postgres;Password=yourpassword"
}
</code></pre>
<h3 id="heading-create-seeding-file">Create Seeding File</h3>
<p>Create a folder in your project called <strong>Infrastructure</strong>. Then within this folder create a file called <code>DbUtilities.cs</code> and populate it with the following code:</p>
<pre><code class="language-csharp">using Dapper;
using Npgsql;
using Microsoft.Extensions.Configuration;

namespace DapperTutorial.Infrastructure;

public static class DBUtilities
{
    private const string CreateUserSql = @"
        CREATE TABLE IF NOT EXISTS ""User"" (
            UserId TEXT PRIMARY KEY,
            Username TEXT,
            FirstName TEXT,
            LastName TEXT,
            Avatar TEXT,
            Email TEXT,
            DOB DATE
        );";

    private const string CreatePostSql = @"
        CREATE TABLE IF NOT EXISTS Post (
            PostId TEXT PRIMARY KEY,
            Likes INTEGER,
            Content TEXT,
            Timestamp TIMESTAMP,
            UserId TEXT,
            FOREIGN KEY(UserId) REFERENCES ""User""(UserId)
        );";

    private const string InsertUsersSql = @"
        INSERT INTO ""User"" (UserId, Username, FirstName, LastName, Avatar, Email, DOB) VALUES
            ('1', 'iron_man', 'Tony', 'Stark', NULL, 'tony.stark@example.com', '1970-05-29'),
            ('2', 'batman', 'Bruce', 'Wayne', NULL, 'bruce.wayne@example.com', '1972-11-11'),
            ('3', 'spiderman', 'Peter', 'Parker', NULL, 'peter.parker@example.com', '1995-08-10'),
            ('4', 'wonderwoman', 'Diana', 'Prince', NULL, 'diana.prince@example.com', '1985-04-02'),
            ('5', 'superman', 'Clark', 'Kent', NULL, 'clark.kent@example.com', '1980-07-18'),
            ('6', 'black-widow', 'Natasha', 'Romanoff', NULL, 'natasha.romanoff@example.com', '1983-06-25'),
            ('7', 'deadpool', 'Wade', 'Wilson', NULL, 'wade.wilson@example.com', '1977-02-19'),
            ('8', 'green-lantern', 'Hal', 'Jordan', NULL, 'hal.jordan@example.com', '1988-09-05'),
            ('9', 'captain-america', 'Steve', 'Rogers', NULL, 'steve.rogers@example.com', '1920-07-04'),
            ('10', 'catwoman', 'Selina', 'Kyle', NULL, 'selina.kyle@example.com', '1982-12-08')
        ON CONFLICT (UserId) DO NOTHING;";

    private const string InsertPostsSql = @"
        INSERT INTO Post (PostId, Likes, Content, Timestamp, UserId) VALUES
            ('p1', 10, 'Hello, world!', '2025-10-12 10:00:00', '1'),
            ('p2', 5, 'My first post!', '2025-10-12 11:00:00', '2'),
            ('p3', 7, 'Excited to join!', '2025-10-12 12:00:00', '3'),
            ('p4', 3, 'What a great day!', '2025-10-12 13:00:00', '4'),
            ('p5', 15, 'Superhero meetup!', '2025-10-12 14:00:00', '5')
        ON CONFLICT (PostId) DO NOTHING;";

    public static async Task SeedDatabaseAsync(IConfiguration configuration)
    {
        var connectionString = configuration.GetConnectionString("DefaultConnection");

        await using var connection = new NpgsqlConnection(connectionString);
        await connection.OpenAsync();

        await using var transaction = await connection.BeginTransactionAsync();

        try
        {
            await connection.ExecuteAsync(CreateUserSql, transaction: transaction);
            await connection.ExecuteAsync(CreatePostSql, transaction: transaction);

            var userCount = await connection.QuerySingleAsync&lt;int&gt;(
                @"SELECT COUNT(*) FROM ""User"";", transaction: transaction);

            var postCount = await connection.QuerySingleAsync&lt;int&gt;(
                "SELECT COUNT(*) FROM Post;", transaction: transaction);

            if (userCount &gt; 0 &amp;&amp; postCount &gt; 0)
            {
                await transaction.CommitAsync();
                return;
            }

            await connection.ExecuteAsync(InsertUsersSql, transaction: transaction);
            await connection.ExecuteAsync(InsertPostsSql, transaction: transaction);

            await transaction.CommitAsync();
        }
        catch (Exception)
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
}
</code></pre>
<p>Add a <strong>seed</strong> endpoint to your API within the <code>Program.cs</code> file as normal:</p>
<pre><code class="language-csharp">// add the using statement
using DapperTutorial.Infrastructure;

// add the seed endpoint
app.MapPost("/seed", async (IConfiguration configuration) =&gt;
{
	try
	{
		await DBUtilities.SeedDatabaseAsync(configuration);
		return Results.Ok("Database seeded successfully.");
	}
	catch (Exception ex)
	{
		return Results.Problem($"An error occurred while seeding the database: {ex.Message}");
	}
});
</code></pre>
<p>In your terminal, run the app with <code>dotnet run</code>, call the <code>/seed</code> endpoint, and this will initiate the database. Check the records have seeded correctly by viewing your database within your preferred database tool.</p>
<h2 id="heading-querying-data-with-dapper">Querying Data With Dapper</h2>
<p>This section of the tutorial will focus on the basics of using the Dapper library to query the database. We'll explore the basics of loading, saving, and protecting your SQL database.</p>
<p>Firstly, we'll implement the <strong>repository pattern</strong>, a commonly used pattern in development. A repository acts as one stop place for all your database functions. Using a repository which implements an interface allows you to easily test and mock your database functionality.</p>
<p>Start by creating the models for your data within a Models folder.</p>
<pre><code class="language-csharp">// User.cs Model
public sealed class User
{
	public string UserId { get; init; } = string.Empty;
	public string Username { get; init; } = string.Empty;
	public string FirstName { get; init; } = string.Empty;
	public string LastName { get; init; } = string.Empty;
	public string? Avatar { get; init; }
	public string Email { get; init; } = string.Empty;
	public DateOnly? DOB { get; init; }
}

// Post.cs Model
public sealed class Post
{
	public string PostId { get; init; } = string.Empty;
	public int Likes { get; init; }
	public string Content { get; init; } = string.Empty;
	public DateTime Timestamp { get; init; }
	public string UserId { get; init; } = string.Empty;
}
</code></pre>
<p>Following best practice, create an<code>IRepository.cs</code> file within an <strong>Application</strong> folder, and paste the following code which defines your querying functions:</p>
<pre><code class="language-csharp">using DapperTutorial.Models;

namespace DapperTutorial.Application;

public interface IRepository
{
    Task&lt;IReadOnlyList&lt;User&gt;&gt; GetUsersAsync();
    Task&lt;User?&gt; GetUserByIdAsync(string userId);
    Task&lt;IReadOnlyList&lt;Post&gt;&gt; GetPostsAsync();
    Task&lt;Post?&gt; GetPostByIdAsync(string postId);
    Task&lt;IReadOnlyList&lt;Post&gt;&gt; GetPostsByUser(string userId);
}
</code></pre>
<p>You now have a base interface, which can be mocked for unit testing purposes within a wider application. This is one of the many perks of implementing this pattern.</p>
<p>Now, create the concrete implementation of the repository like so:</p>
<pre><code class="language-csharp">using Dapper;
using DapperTutorial.Application;
using DapperTutorial.Models;
using Npgsql;

namespace DapperTutorial.Infrastructure;

public class Repository(IConfiguration configuration) : IRepository
{
	private readonly string _connectionString = configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Missing connection string: ConnectionStrings:DefaultConnection");

	public async Task&lt;IReadOnlyList&lt;User&gt;&gt; GetUsersAsync()
	{
		const string sql = @"
			SELECT
				UserId,
				Username,
				FirstName,
				LastName,
				Avatar,
				Email,
				DOB
			FROM ""User""
			ORDER BY Username;";

		await using var connection = CreateConnection();
		var users = await connection.QueryAsync&lt;User&gt;(sql);
		return users.AsList();
	}

	public async Task&lt;User?&gt; GetUserByIdAsync(string userId)
	{
		const string sql = @"
			SELECT
				UserId,
				Username,
				FirstName,
				LastName,
				Avatar,
				Email,
				DOB
			FROM ""User""
			WHERE UserId = @UserId;";

		await using var connection = CreateConnection();
		return await connection.QuerySingleOrDefaultAsync&lt;User&gt;(sql, new { UserId = userId });
	}

	public async Task&lt;IReadOnlyList&lt;Post&gt;&gt; GetPostsAsync()
	{
		const string sql = @"
			SELECT
				PostId,
				Likes,
				Content,
				Timestamp,
				UserId
			FROM Post
			ORDER BY Timestamp DESC;";

		await using var connection = CreateConnection();
		var posts = await connection.QueryAsync&lt;Post&gt;(sql);
		return posts.AsList();
	}

	public async Task&lt;IReadOnlyList&lt;Post&gt;&gt; GetPostsByUser(string userId)
	{
		const string sql = @"
			SELECT
				PostId,
				Likes,
				Content,
				Timestamp,
				UserId
			FROM Post
			WHERE UserId = @UserId
			ORDER BY Timestamp DESC;";

		await using var connection = CreateConnection();
		var posts = await connection.QueryAsync&lt;Post&gt;(sql, new { UserId = userId });
		return posts.AsList();
	}

	public async Task&lt;Post?&gt; GetPostByIdAsync(string postId)
	{
		var sql = @"
			SELECT * FROM Post
			WHERE PostId = @PostId;";

		await using var connection = CreateConnection();
		return await connection.QuerySingleOrDefaultAsync&lt;Post&gt;(sql, new { PostId = postId });
	}

	private NpgsqlConnection CreateConnection() =&gt; new(_connectionString);
}
</code></pre>
<h4 id="heading-unpacking-the-repository">Unpacking the Repository:</h4>
<p>The primary constructor injects <code>IConfiguration</code>, which is automatically provided by ASP.Net Core's built-in dependency injection system. This means you don't need to instantiate it yourself – the framework handles that for you. This allows access to the connection string defined in <code>appsettings.json</code>, which Dapper needs in order to connect to the database.</p>
<p>You'll also notice the null-coalescing <code>??</code> operator. This is a defensive pattern that throws a clear, descriptive error immediately if the connection string is missing, rather than letting a cryptic <code>NullReferenceException</code> surface somewhere further down the line when trying to use the connection string's value, if not provided.</p>
<p>Each method contains a SQL string prefixed with the <code>@</code> character, making it a verbatim string literal. This allows the string to span multiple lines without needing <code>\n</code> escape characters or string concatenation, so we can format our SQL the same way we would in a query editor. This makes it much easier to read.</p>
<p><code>User</code> is a reserved word in PostgreSQL, hence the double quotes around <code>"User"</code>.</p>
<p>If you're familiar with SQL, you can easily use Dapper's query methods. This is the key strength of Dapper: it gives you the flexibility of plain SQL, with the added benefits of an ORM.</p>
<ul>
<li><p><code>QueryAsync()</code>: Use this method when your query could return zero or more results. It will always return a collection, never null, so you don't need to worry about null checks when no rows are found.</p>
</li>
<li><p><code>QuerySingleOrDefaultAsync()</code>: Use this method when you expect at most one result. This is useful for methods like <code>GetByIdAsync</code>, or fetching a user's profile. If no matching row is found, it returns the default value for that type – <code>null</code> for reference types like <code>User?</code>.</p>
</li>
</ul>
<h2 id="heading-querysingle-vs-queryfirst">QuerySingle vs QueryFirst</h2>
<p>Both <code>QuerySingleOrDefaultAsync</code> and <code>QueryFirstOrDefaultAsync</code> are used when you want to return a single result, and both return the default value for the type of <code>null</code> for reference types, when no rows are found.</p>
<p>The difference is in how they behave when <strong>more than one row is returned</strong>.</p>
<p><code>QuerySingleOrDefaultAsync</code> will throw an exception, which makes it the safer choice when querying by primary key, as if you ever get two results back, something has gone seriously wrong and you want to know about it immediately rather than silently returning the wrong record, such as incorrect duplicate.</p>
<p><code>QueryFirstOrDefaultAsync</code>, on the other hand, takes the first result and ignores the rest. This makes it the better fit for scenarios such as "<em>give me the most recent post by this user</em>", where multiple results are expected yet you just want the top one, typically driven by an <code>ORDER BY</code> in your query.</p>
<h2 id="heading-writing-data-with-dapper">Writing Data With Dapper</h2>
<p>You have successfully created methods for querying and returning data from the repository, but you're going to require methods for inserting and updating existing records.</p>
<h3 id="heading-insert-method">Insert Method</h3>
<p>Add a <code>CreateUserAsync()</code> method definition to the <code>IRepository</code> interface, and then copy the below implementation into your <code>Repository.cs</code>:</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; CreateUserAsync(User user)
{
    const string sql = @"
        INSERT INTO ""User"" (
            UserId,
            Username,
            FirstName,
            LastName,
            Avatar,
            Email,
            DOB
        ) VALUES (
            @UserId,
            @Username,
            @FirstName,
            @LastName,
            @Avatar,
            @Email,
            @DOB
        );";

    await using var connection = CreateConnection();
    var rowsAffected = await connection.ExecuteAsync(sql, user);
    return rowsAffected &gt; 0;
}
</code></pre>
<p>As before, state the SQL for inserting a record into the User table, with the parameters needed to assign the values.</p>
<p>A few things worth noting:</p>
<ul>
<li><p>Dapper maps the <code>user</code> object's properties directly to the <code>@</code> parameters by name, so you can just pass <code>user</code> rather than constructing an anonymous object.</p>
</li>
<li><p><code>ExecuteAsync()</code> returns the number of rows affected, so returning <code>rowsAffected &gt; 0</code> gives the caller a simple success/failure bool.</p>
</li>
<li><p><code>Avatar</code> and <code>DOB</code> are nullable on the model, and Dapper handles this gracefully: it will insert <code>NULL</code> into the database when those values are <code>null</code>.</p>
</li>
</ul>
<h3 id="heading-protecting-your-database-parameterisation-and-sql-injection">Protecting Your Database – Parameterisation and SQL Injection</h3>
<p>You may have noticed that throughout this tutorial, values are never inserted directly into the SQL string. Instead, we use placeholders like <code>@UserId</code> and <code>@Username</code>, with the actual values passed separately. This is called <strong>parameterisation</strong>, and it's one of the most important habits you can build as a developer.</p>
<p>To understand why, consider what happens without it. If you were to build a query using string interpolation:</p>
<pre><code class="language-csharp">// Never do this
var sql = $"SELECT * FROM \"User\" WHERE Username = '{username}'";


//A malicious user could pass the following as their username:
```
' OR '1'='1
</code></pre>
<p>Which would turn your query into:</p>
<pre><code class="language-sql">SELECT * FROM "User" WHERE Username = '' OR '1'='1'
</code></pre>
<p>Since <code>'1'='1'</code> is always true, this query returns every user in the database. With a more destructive payload, an attacker could drop tables, delete records, or extract sensitive data entirely. This is known as a <strong>SQL injection attack</strong>, and it remains one of the most common and damaging vulnerabilities in web applications.</p>
<p>Dapper protects you from this automatically. When you write:</p>
<pre><code class="language-csharp">const string sql = @"SELECT * FROM ""User"" WHERE Username = @Username";
var user = await connection.QuerySingleOrDefaultAsync&lt;User&gt;(sql, new { Username = username });
</code></pre>
<p>Dapper sends the SQL and the values to the database separately. The database receives the query structure first, compiles it, and then applies the value as pure data – it can never be interpreted as SQL. No matter what a user passes in, it will always be treated as a value, never as an instruction.</p>
<p>This is why throughout this tutorial, you will always see:</p>
<ul>
<li><p><code>@ParameterName</code> placeholders in the SQL string</p>
</li>
<li><p>Values passed as an anonymous object, a model, or <code>DynamicParameters</code></p>
</li>
</ul>
<p>But never string interpolation or concatenation inside a SQL string.</p>
<h2 id="heading-updating-data-with-dapper">Updating Data With Dapper</h2>
<p>You don't always want to create new records. Sometimes, you would rather update records instead. Below is the code required to do this. Add this method to your repository, not forgetting to add the definition to the repository interface:</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; UpdateUserAsync(User user)
	{
        const string sql = @"
        UPDATE ""User"" SET
            Username = @Username,
            FirstName = @FirstName,
            LastName = @LastName,
            Avatar = @Avatar,
            Email = @Email,
            DOB = @DOB
        WHERE UserId = @UserId;";

		await using var connection = CreateConnection();
		var affectedRows = await connection.ExecuteAsync(sql, user);
		return affectedRows &gt; 0;
	}
</code></pre>
<p>Like all other queries / actions with Dapper, an SQL command is written and passed to <code>ExecuteAsync()</code> along with the object to be updated, and Dapper will automatically map the properties based on name.</p>
<h2 id="heading-deleting-records-with-dapper">Deleting Records With Dapper</h2>
<p>Just like before, add the following code to your repository. Add your delete SQL command, and pass to the <code>ExecuteAsync()</code> method. Below, instead of passing the user object, you're manually mapping the userId to the SQL <code>`@UserId`</code> parameter.</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; DeleteUserAsync(string userId)
	{
		const string sql = @"
			DELETE FROM ""User""
			WHERE UserId = @UserId;";

		await using var connection = CreateConnection();
		var affectedRows = await connection.ExecuteAsync(sql, new { UserId = userId });
		return affectedRows &gt; 0;
	}
</code></pre>
<p>There may be a time where you don't want to delete one record at a time, and instead would like to delete multiple in one go. This can be achieved by Dapper's internal mechanics, and passing a list of items to the <code>ExecuteAsync()</code> method, like so:</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; DeleteUsersBatchAsync(IEnumerable&lt;string&gt; userIds)
{
    const string sql = @"
        DELETE FROM ""User""
        WHERE UserId = @UserId;";

    await using var connection = CreateConnection();
    var affectedRows = await connection.ExecuteAsync(sql, userIds.Select(id =&gt; new { UserId = id }));

    return affectedRows &gt; 0;
}
</code></pre>
<p>Dapper will iterate over the collection and execute the statement once per item. It's not a single batch query under the hood it's multiple executions, so for large datasets you'd want to consider a different approach – but for typical use cases it's clean and convenient.</p>
<h2 id="heading-batch-processing-with-dapper">Batch Processing With Dapper</h2>
<p>For true batch processing in a single round trip, you would need to lean on SQL rather than Dapper itself. Dapper is just the messenger here, and the batching logic lives in the query.</p>
<p>The most common approach is using <code>In / Any</code> (depending on SQL database flavour):</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; DeleteUsersAsync(IEnumerable&lt;string&gt; userIds)
{
    const string sql = @"
        DELETE FROM ""User""
        WHERE UserId = ANY(@UserIds);";

    await using var connection = CreateConnection();
    var affectedRows = await connection.ExecuteAsync(sql, new { UserIds = userIds.ToArray() });
    return affectedRows &gt; 0;
}
</code></pre>
<p>This sends a single query to the database with all the IDs, rather than one query per ID. Npgsql supports passing an array directly to <code>ANY()</code>, which is the PostgreSQL idiom for this.</p>
<p><strong>Note:</strong> <code>ANY(@UserIds)</code> is PostgreSQL-specific syntax. If you were using SQL Server you'd use <code>WHERE UserId IN @UserIds</code> instead – Dapper has built-in support for expanding <code>IN</code> parameters when passed an <code>IEnumerable</code>.</p>
<p>In summary:</p>
<ul>
<li><p><strong>Multiple executions</strong>: one round trip per item, simple but inefficient at scale, especially when deleting a lot of users, or their posts.</p>
</li>
<li><p><code>ANY</code> <strong>/</strong> <code>IN</code>: single round trip regardless of list size, much more efficient for larger datasets.</p>
</li>
</ul>
<p>For most everyday use cases, the difference won't matter. But it's a good habit to reach for the single query approach when you know you're dealing with a collection.</p>
<div>
<div>💡</div>
<div>Remember to keep the <code>IRepository</code> interface updated with any new methods you've learnt within this tutorial so far</div>
</div>

<h2 id="heading-transactions-with-dapper"><strong>Transactions With Dapper</strong></h2>
<p>If you cast your mind back to the seeding utility, you may have noticed a transaction was already being used there. Now it's time to understand what they are and why they matter.</p>
<p>A transaction guarantees that either <strong>all</strong> operations succeed, or <strong>none</strong> of them do. This is the atomicity principle: the database will never be left in a half-finished state.</p>
<p>Imagine the scenario where a new user signs up to the social media application, and you ask them to write their first post, during the registration process – meaning their account and their first post is stored in the same operation.</p>
<p>Without a transaction, if the user insert succeeds but the post insert fails, you're left with an orphaned user record in the database – an account with no post, and no way to know something went wrong.</p>
<p>If you're familiar with SQL, you may have written transactions directly like so:</p>
<pre><code class="language-sql">BEGIN TRANSACTION;
    INSERT INTO "User" (UserId, Username ...) VALUES (...);
    INSERT INTO Post (PostId, ...) VALUES (...);
COMMIT;
</code></pre>
<p>With Dapper, rather than writing the transaction logic inside the SQL itself, you manage it from your C# code instead. Each SQL statement stays as its own focused block, and you wrap them together in a transaction at the application level. This gives you the same atomicity guarantee, but with the added benefit of being able to use C#'s <code>try/catch</code> to handle failures and trigger a rollback cleanly.</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; CreateUserWithPostAsync(User user, Post post)
{
    const string insertUserSql = @"
        INSERT INTO ""User"" (UserId, Username, FirstName, LastName, Avatar, Email, DOB)
        VALUES (@UserId, @Username, @FirstName, @LastName, @Avatar, @Email, @DOB);";

    const string insertPostSql = @"
        INSERT INTO Post (PostId, Likes, Content, Timestamp, UserId)
        VALUES (@PostId, @Likes, @Content, @Timestamp, @UserId);";

    await using var connection = CreateConnection();
    await connection.OpenAsync();
    await using var transaction = await connection.BeginTransactionAsync();

    try
    {
        await connection.ExecuteAsync(insertUserSql, user, transaction);
        await connection.ExecuteAsync(insertPostSql, post, transaction);
        await transaction.CommitAsync();
        return true;
    }
    catch (Exception)
    {
        await transaction.RollbackAsync();
        return false;
    }
}
</code></pre>
<p>It also means you can write some useful methods, which run particular SQL blocks conditionally. Take the below example: there are 3 different SQL blocks which can be run as part of the transaction <code>insertUserSql</code>, <code>insertPostSql</code> and <code>logActivitySql</code>.</p>
<p>For the below example, imagine you have an <code>ActivityLog</code> table that tracks user actions across the application. All three blocks are part of the same transaction, but only two of them are guaranteed to run. If the flag is inactive, the activity log is skipped entirely, and the transaction commits with just the user and post. If anything fails, all of it rolls back regardless.</p>
<pre><code class="language-csharp">public async Task&lt;bool&gt; CreateUserWithPostAndLogAsync(User user, Post post, bool logActivity)
{
    const string insertUserSql = @"
        INSERT INTO ""User"" (UserId, Username, FirstName, LastName, Avatar, Email, DOB)
        VALUES (@UserId, @Username, @FirstName, @LastName, @Avatar, @Email, @DOB);";

    const string insertPostSql = @"
        INSERT INTO Post (PostId, Likes, Content, Timestamp, UserId)
        VALUES (@PostId, @Likes, @Content, @Timestamp, @UserId);";

    const string logActivitySql = @"
        INSERT INTO ActivityLog (UserId, Action, Timestamp)
        VALUES (@UserId, 'SIGNUP', @Timestamp);";

    await using var connection = CreateConnection();
    await connection.OpenAsync();
    await using var transaction = await connection.BeginTransactionAsync();

    try
    {
        await connection.ExecuteAsync(insertUserSql, user, transaction);
        await connection.ExecuteAsync(insertPostSql, post, transaction);

        if (logActivity)
        {
            await connection.ExecuteAsync(logActivitySql, new { user.UserId, Timestamp = DateTime.UtcNow }, transaction);
        }

        await transaction.CommitAsync();
        return true;
    }
    catch (Exception)
    {
        await transaction.RollbackAsync();
        return false;
    }
}
</code></pre>
<h2 id="heading-multi-mapping-splits"><strong>Multi-mapping / Splits</strong></h2>
<p>So far, every query has returned data from a single table, mapped to a single object. But real applications rarely work that way. Data is relational, and you'll frequently need to query across multiple tables at once using a <strong>JOIN</strong>.</p>
<p>Dapper handles this through <strong>multi-mapping</strong>, which allows a single query to map results across multiple objects simultaneously. To demonstrate this, you're going to return a list of posts with their associated author's details populated (rather than just a <code>UserId</code> foreign key reference).</p>
<p>First, create the model used to store the combined data in your Models folder.</p>
<pre><code class="language-csharp">public sealed class PostWithAuthor
{
    public Post Post { get; init; } = null!;
    public User Author { get; init; } = null!;
}
</code></pre>
<p>Now add the following method to your repository (not forgetting to always add the method definition to your interface too).</p>
<pre><code class="language-csharp">public async Task&lt;IReadOnlyList&lt;PostWithAuthor&gt;&gt; GetPostsWithAuthorsAsync()
{
    const string sql = @"
        SELECT
            p.PostId,
            p.Likes,
            p.Content,
            p.Timestamp,
            p.UserId,
            u.UserId,
            u.Username,
            u.FirstName,
            u.LastName,
            u.Avatar,
            u.Email,
            u.DOB
        FROM Post p
        INNER JOIN ""User"" u ON p.UserId = u.UserId
        ORDER BY p.Timestamp DESC;";

    await using var connection = CreateConnection();

    var results = await connection.QueryAsync&lt;Post, User, PostWithAuthor&gt;(
        sql,
        (post, user) =&gt; new PostWithAuthor { Post = post, Author = user },
        splitOn: "UserId"
    );

    return results.AsList();
}
</code></pre>
<p>There is quite a bit going on here compared to the queries you have written so far, so let's unpack it.</p>
<h3 id="heading-select-statement"><strong>SELECT Statement</strong></h3>
<p>Unlike previous queries where you could rely on <code>SELECT *</code>, column order matters here. Dapper needs to know where the <code>Post</code> columns end and the <code>User</code> columns begin in the result set. You're explicitly listing every column, with all <code>Post</code> columns first and all <code>User</code> columns second.</p>
<pre><code class="language-csharp">QueryAsync&lt;Post, User, PostWithAuthor&gt;
</code></pre>
<p>Rather than a single generic type, you are now passing three: the first two are the objects you want to map to, and the third is the return type. Dapper will split the result set into a <code>Post</code> and a <code>User</code>, and hand both to you to combine however you like.</p>
<h3 id="heading-the-mapping-function">The Mapping Function</h3>
<pre><code class="language-csharp">(post, user) =&gt; new PostWithAuthor { Post = post, Author = user }
</code></pre>
<p>This is where you stitch the two objects together. Dapper passes you the mapped <code>Post</code> and <code>User</code> for each row, and you return the combined <code>PostWithAuthor</code>. This is also where you have full control: if you wanted to flatten the result into a single object rather than a nested one, you could do that here instead.</p>
<pre><code class="language-csharp">splitOn: "UserId"
</code></pre>
<p>This is the most important part to understand. The <code>splitOn</code> parameter tells Dapper the name of the column where the first object ends and the second begins. In this case, when Dapper encounters <code>UserId</code> for the second time in the result set, it knows everything from that point onwards belongs to the <code>User</code> object.</p>
<p>It defaults to <code>Id</code> – so if your split column were named <code>Id</code>, you wouldn't need to specify it at all. Since both <code>Post</code> and <code>User</code> share <code>UserId</code> as their identifier, you must specify it explicitly here.</p>
<h4 id="heading-a-common-mistake">A Common Mistake</h4>
<p>Because <code>splitOn</code> works by column position, the column you split on must be the <strong>first column of the second object</strong> in your SELECT. If <code>u.UserId</code> were not the first <code>User</code> column listed, Dapper would split in the wrong place and you'd end up with incorrectly mapped data. It's the kind of bug that can be tricky to spot because no exception is thrown, the data is just wrong.</p>
<h2 id="heading-what-comes-next-possible-additions">What Comes Next – Possible Additions</h2>
<p>Use this tutorial as a base to build upon. The next steps are to look at how you could structure your project to make your repository tidier. For example, you could move your SQL commands into files of their own, and import them in to your repository, making your repository code slimmer.</p>
<p>To avoid this tutorial becoming too bloated, I tried to cover the key features of Dapper. Now you know the fundamentals, you could push your learning further to cover:</p>
<ul>
<li><p><code>QueryMultiple</code>: execute several SQL statements in a single round trip. This is ideal for dashboard-style endpoints.</p>
</li>
<li><p><strong>Dynamic parameters</strong>: build queries conditionally using <code>DynamicParameters</code>, which is useful for search and filter scenarios.</p>
</li>
<li><p><strong>Endpoint implementation</strong>: add API endpoints to call your repository methods, injecting the <code>IRepository</code> into your minimal endpoints.</p>
<p>For example:</p>
</li>
</ul>
<pre><code class="language-csharp">app.MapPost("/insert-user", async (IRepository repository, User newUser) =&gt;
{
	var success = await repository.InsertUserAsync(newUser);
	return success
		? Results.Ok($"User {newUser.Username} inserted successfully.")
		: Results.Problem("Failed to insert user.");
});
</code></pre>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Dapper won't be the right tool for every project. If you're working with complex entity relationships, frequent schema changes, or a team heavily invested in LINQ, Entity Framework may be the better fit. And there's nothing wrong with that.</p>
<p>But when performance matters, when you need precise control over what's hitting your database, or when you're working with a schema you don't own, Dapper's transparency is hard to beat. You always know exactly what query is being executed, because you wrote it yourself.</p>
<p>The trade-off is straightforward: Entity Framework gives you speed of development, Dapper gives you speed of execution. Understanding both makes you a more well-rounded .NET developer – and knowing when to reach for each one is a skill in itself.</p>
<p>If you already know SQL, Dapper's learning curve is remarkably shallow. There's no magic, no conventions to memorise, no generated queries to second-guess. Just SQL, mapped cleanly to your C# objects, and as this tutorial has hopefully shown, that doesn't have to mean unsafe or hard to maintain.</p>
<p>Again, thanks for reading and I hope you have found this tutorial useful. If you'd like to chat about anything in this tutorial or hear about future articles, you can follow me on <a href="https://x.com/grant-dot-dev">X/Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Reusable Modular Unity Packages to Speed Up Development ]]>
                </title>
                <description>
                    <![CDATA[ How many times have you rewritten the same systems across different Unity projects? Or copied entire folders from an old project, only to spend hours fixing references, renaming namespaces, and adapti ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-reusable-modular-unity-packages-to-speed-up-development/</link>
                <guid isPermaLink="false">6998ee96a20b74e093d7e671</guid>
                
                    <category>
                        <![CDATA[ unity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ modularity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Talha Cagatay ISIK ]]>
                </dc:creator>
                <pubDate>Fri, 20 Feb 2026 23:30:30 +0000</pubDate>
                <media:content url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5e1e335a7a1d3fcc59028c64/7a3eeaef-4bab-403c-b9ef-3ebc785efb2f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>How many times have you rewritten the same systems across different Unity projects? Or copied entire folders from an old project, only to spend hours fixing references, renaming namespaces, and adapting the code to fit a slightly different architecture?</p>
<p>That repetition doesn’t just waste time – it slows down your development and creates maintenance headaches across projects.</p>
<p>This guide walks you through a set of reusable, modular Unity packages you can drop into any project to speed up development. You’ll build them once as packages and install them via Git wherever you need them, instead of reimplementing the same systems every time.</p>
<p>The article covers four core packages:</p>
<ol>
<li><p><strong>com.core.initializer</strong> – Finds and initializes your game controllers at runtime (MVC-style) so startup and dependencies centralized.</p>
</li>
<li><p><strong>com.core.data</strong> – Handles local (and optionally cloud) save data using MemoryPack binary serialization and a provider abstraction so you can switch or extend storage backends.</p>
</li>
<li><p><strong>com.core.ui</strong> – Manages popups and full-screen UIs in a consistent way so you can show dialogs, panels, and screens without duplicating logic.</p>
</li>
<li><p><strong>com.core.dotween</strong> – Wraps the DoTween tween engine as a Unity package so <strong>com.core.ui</strong> (and other packages) can reference it for animations.</p>
</li>
</ol>
<p>In this tutorial, we’ll build all four packages step by step. The Initializer, Data, UI, and DoTween packages are all documented so you can easily follow along. All packages are also upload to github which you can find the links at the end.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a href="#heading-what-you-will-learn">What You Will Learn</a></p>
</li>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-set-up-your-development-project">Set Up Your Development Project</a></p>
</li>
<li><p><a href="#heading-package-1-the-initializer">Package 1: The Initializer Package</a></p>
</li>
<li><p><a href="#heading-package-2-the-data-package">Package 2: The Data Package</a></p>
</li>
<li><p><a href="#heading-package-3-comcoredotween">Package 3: The DoTween Package</a></p>
</li>
<li><p><a href="#heading-package-4-the-ui-package">Package 4: The UI Package</a></p>
</li>
<li><p><a href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-you-will-learn"><strong>What You Will Learn</strong></h2>
<ul>
<li><p>How to create a Unity package with the Package Manager</p>
</li>
<li><p>How to set up the package structure</p>
</li>
<li><p>How to built a centralized initialization flow for your packages</p>
</li>
<li><p>How to use UniTask for async initialization on Unity's main thread</p>
</li>
<li><p>How the Data package uses <code>IDataProvider</code> and <strong>MemoryPack</strong> for local save/load</p>
</li>
<li><p>How the UI package uses popups (stack) and screens (single active) with DoTween animations</p>
</li>
</ul>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>Before you start, make sure you have:</p>
<ul>
<li><p>Unity installed (any Long Term Support version compatible with the packages. The referenced packages target Unity 6000.3)</p>
</li>
<li><p>Git installed</p>
</li>
<li><p>Jetbrains Rider or Visual Studio Community installed</p>
</li>
<li><p>Know how to use Unity game engine</p>
</li>
<li><p>Know C# and async/await structures</p>
</li>
</ul>
<p>You will use the Unity Package Manager to create packages, then upload and install them via Git in other projects.</p>
<h2 id="heading-set-up-your-development-project"><strong>Set Up Your Development Project</strong></h2>
<p>Create a new Unity project if you don’t already have one. We’ll use it as a playground to build and test your packages. This project (and not the packages themselves) is your development environment.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770938731026/c2afbae6-69a7-4cd2-a2c3-2d43b0c68fe6.png" alt="Creating a new unity project via Unity Hub" width="2113" height="1344" loading="lazy">

<h2 id="heading-package-1-the-initializer"><strong>Package 1: The Initializer</strong></h2>
<p>The first package is <strong>com.core.initializer</strong>. It finds all your controllers, runs their async initialization before the first scene loads, and lets the rest of the game access them via a single handler.</p>
<h3 id="heading-what-comcoreinitializer-does">What com.core.initializer Does</h3>
<ul>
<li><p><strong>Early initialization</strong>: Runs at <code>RuntimeInitializeLoadType.BeforeSceneLoad</code>, so all controllers exist and are initialized before the first scene loads.</p>
</li>
<li><p><strong>Central access</strong>: Stores each controller by its type and exposes them through a type-safe getter.</p>
</li>
<li><p><strong>Completion signaling</strong>: Exposes a static event (<code>ControllersInitialized</code>) and a <code>UniTaskCompletionSource</code> (<code>InitializationCompleted</code>) so you can run code only after all controllers have finished initializing.</p>
</li>
</ul>
<h3 id="heading-create-the-initializer-package">Create the Initializer Package</h3>
<p>To start, open Window → Package Manager (under Package Management). Then click the + button and choose Create package.</p>
<p>Name the package <code>com.core.initializer</code> (or your preferred name).</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770939190680/3d9d3c0e-94f7-40bf-b5b7-d3d05ff90301.png" alt="Opening Unity Package Manager" width="907" height="630" loading="lazy">

<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771030017622/bc551fb9-69d5-4fa6-8309-293fd34d6cc5.png" alt="Creating a new package" width="928" height="579" loading="lazy">

<p>Unity creates the essential package files for you.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770939568125/86637464-89c7-4dc6-861b-cb071cc2d942.png" alt="Example package folders and files" width="607" height="563" loading="lazy">

<p>You can edit <code>package.json</code> and the assembly definition (asmdef) names to match your naming. The full set of changes is not listed here. The final package is available on GitHub (linked at the end).</p>
<h3 id="heading-add-the-unitask-dependency">Add the UniTask Dependency</h3>
<p>Unity runs on the main thread, and C# Tasks can be problematic in that context. They don’t know about the Unity Editor's play state and keep running after exiting play mode for example. So you’ll need to handle these cases manually. For these reasons, this package uses <a href="https://github.com/Cysharp/UniTask">UniTask</a> instead of C# Tasks for async operations.</p>
<p>Git-based dependencies are supported at the project level but not at the package level. Add UniTask via OpenUPM by following the <a href="https://openupm.com/packages/com.cysharp.unitask/#modal-manualinstallation">manual installation steps</a>.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770988159264/9d2db898-9e1f-4514-aeda-53fb4a190045.png" alt="Adding OpenUPM and UniTask to scoped registries" width="1006" height="746" loading="lazy">

<p>Add UniTask as a dependency in package.json of initializer package:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/698d2f3c217bebae73c3f5e8/035b9242-f111-4c96-8483-4b02452a13bc.png" alt="package.json file of initializer package" width="377" height="292" loading="lazy">

<pre><code class="language-json">"dependencies": {
  "com.cysharp.unitask": "2.5.10"
}
</code></pre>
<p>Also reference UniTask in the asmdef file.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771255181446/9812cea2-d278-4920-88e5-43e89cd41a91.png" alt="Referencing UniTask within Initializer package's asmdef file" width="882" height="470" loading="lazy">

<p>You’ll need to follow this dependency flow for the rest of the packages you create.</p>
<h3 id="heading-implement-the-package-structure">Implement the Package Structure</h3>
<p>The initializer uses an MVC-like architecture. Controllers handle both initialization and game logic. You could later split initialization into services and keep business logic in controllers (for example, an MVCS-style setup). This tutorial keeps things simple and uses only controllers.</p>
<p>Target layout:</p>
<ul>
<li><p><strong>Runtime/Interface/</strong> – <code>IController</code></p>
</li>
<li><p><strong>Runtime/Helper/</strong> – <code>Creator</code> (reflection-based instance creation)</p>
</li>
<li><p><strong>Runtime/</strong> – <code>ControllerHandler</code> (orchestrates initialization)</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771255216106/90741270-2166-4694-874f-fcc7aec539fe.png" alt="Initializer package final folders and files" width="434" height="543" loading="lazy">

<p>All controllers implement the <code>IController</code> interface. The <code>Initialize</code> method returns a <code>UniTask</code> so initialization can be async on the main thread.</p>
<pre><code class="language-csharp">using Cysharp.Threading.Tasks;

namespace com.core.initializer
{
    public interface IController
    {
        bool IsInitialized { get; }

        UniTask Initialize();
    }
}
</code></pre>
<h3 id="heading-create-the-creator-helper">Create the Creator Helper</h3>
<p>You’ll need to find all types that implement <code>IController</code>, create instances of them at runtime, and also find MonoBehaviours that implement <code>IController</code> (since those cannot be created via reflection). The <code>Creator</code> class does both.</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace com.core.initializer
{
    public static class Creator
    {
        /// &lt;summary&gt;
        /// Creates instances of every type which inherits from T interface.
        /// &lt;/summary&gt;
        public static IEnumerable&lt;T&gt; CreateInstancesOfType&lt;T&gt;(params Type[] exceptTypes)
        {
            var interfaceType = typeof(T);

            var result = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x =&gt; x.GetTypes()).Where
                (
                 x =&gt; interfaceType.IsAssignableFrom(x) &amp;&amp;
                      !x.IsInterface                    &amp;&amp;
                      !x.IsAbstract                     &amp;&amp;
                      exceptTypes.All(type =&gt; !x.IsSubclassOf(type) &amp;&amp; x != type)
                ).Select(Activator.CreateInstance);

            return result.Cast&lt;T&gt;();
        }

        public static IEnumerable&lt;T&gt; GetMonoControllers&lt;T&gt;() =&gt; UnityEngine.Object.FindObjectsByType&lt;MonoBehaviour&gt;(FindObjectsInactive.Include, FindObjectsSortMode.None).OfType&lt;T&gt;();
    }
}
</code></pre>
<p>Using reflection at runtime has some overhead. You can optimize this later with baking the reflection in editor and using it at runtime. For MonoBehaviours, <code>FindObjectsByType</code> is used here for simplicity. In a larger project, you might use a dependency injection solution such as <a href="https://github.com/hadashiA/VContainer">VContainer</a> or <a href="https://github.com/gustavopsantos/Reflex">Reflex</a>.</p>
<h3 id="heading-implement-the-controllerhandler">Implement the ControllerHandler</h3>
<p>The <code>ControllerHandler</code> uses <code>Creator</code> to gather all <code>IController</code> instances (both reflection-created and MonoBehaviours), initializes them in order, and exposes an event and a <strong>UniTaskCompletionSource</strong> so the rest of the game can wait for startup to finish.</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using Cysharp.Threading.Tasks;
using UnityEngine;

namespace com.core.initializer
{
    public class ControllerHandler
    {
        public static readonly UniTaskCompletionSource InitializationCompleted = new();

        public static event Action ControllersInitialized;

        private static Dictionary&lt;Type, IController&gt; _controllers = new();

        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        public static async void Initialize()
        {
            var controllers = Creator.CreateInstancesOfType&lt;IController&gt;(typeof(MonoBehaviour)).ToList();
            controllers.AddRange(Creator.GetMonoControllers&lt;IController&gt;());

            Debug.Log("Initializing controller");

            foreach (var controller in controllers)
            {
                Debug.Log($"&lt;color=yellow&gt;Initializing {controller.GetType().Name}&lt;/color&gt;");
                await controller.Initialize();
                _controllers.Add(controller.GetType(), controller);
                Debug.Log($"&lt;color=green&gt;Initialized {controller.GetType().Name}&lt;/color&gt;");
            }

            Debug.Log("&lt;color=green&gt;All controllers are initialized&lt;/color&gt;");
            ControllersInitialized?.Invoke();
            InitializationCompleted?.TrySetResult();
        }

        public static T GetController&lt;T&gt;() where T : class, IController =&gt; _controllers[typeof(T)] as T;
    }
}
</code></pre>
<h3 id="heading-how-to-test-the-initializer">How to Test the Initializer</h3>
<ol>
<li><p>Create a class that implements <code>IController</code> (or a MonoBehaviour that implements it).</p>
</li>
<li><p>Implement <code>Initialize()</code> with your setup logic (you can use <code>await</code> and UniTask).</p>
</li>
<li><p>After initialization, access the controller with:<br><code>var myController = ControllerHandler.GetController&lt;MyController&gt;();</code></p>
</li>
</ol>
<p>You can also subscribe to <code>ControllerHandler.ControllersInitialized</code> or await <code>ControllerHandler.InitializationCompleted.Task</code> to run code after all controllers are ready.</p>
<p>There are some limitations here. First, it can be hard to handle dependencies between different controllers. Second, it’s easy to run into circular dependencies.</p>
<p>When you check the <a href="https://github.com/TalhaCagatay/com.core.initializer">GitHub repo</a>, a DI framework may already be implemented to address these limitations. Make sure to open an issue if you want this feature.</p>
<h2 id="heading-package-2-the-data-package">Package 2: The Data Package</h2>
<p>com.core.data handles local saving with a binary serializer. The package uses <a href="https://github.com/Cysharp/MemoryPack">MemoryPack</a> for fast, binary serialization and defines an <code>IDataProvider</code> interface so you can plug in different providers (local, cloud, or hybrid).</p>
<p><strong>Package dependency:</strong> <code>com.cysharp.memorypack</code> (version 1.10.0). Add it to your project via OpenUPM and add it to package.json and the asmdef for com.core.data.</p>
<p>Create a new package and name it com.core.data. Use a structure such as:</p>
<ul>
<li><p><strong>Runtime/Interface/</strong> – <code>IDataProvider</code></p>
</li>
<li><p><strong>Runtime/Providers/</strong> – <code>LocalDataProvider</code></p>
</li>
<li><p><strong>Runtime/</strong> – optional sample <code>DataController</code> (in your game assembly) that implements <code>IController</code> and uses an <code>IDataProvider</code></p>
</li>
</ul>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/698d2f3c217bebae73c3f5e8/b6192b39-04d1-4c5a-90e6-b0ed9f1a4ce4.png" alt="Adding MemoryPack to scoped registries" style="display:block;margin:0 auto" width="1214" height="747" loading="lazy">

<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771266043719/9cd79a74-4a72-4882-b803-8c53ca95eaa0.png" alt="Data package final folders and files" width="353" height="467" loading="lazy">

<p>All data providers use the IDataProvider interface.</p>
<pre><code class="language-csharp">using Cysharp.Threading.Tasks;

namespace com.core.data
{
    public interface IDataProvider
    {
        bool     IsInitialized { get; }
        void     Save&lt;T&gt;(string key, T data);
        T        Load&lt;T&gt;(string key, T defaultValue = default);
        bool     HasKey(string  key);
        string[] GetKeys();
        UniTask  Delete(string key);
        UniTask  DeleteAll();
    }
}
</code></pre>
<p>You will use UniTask in the data package as well. Add com.cysharp.unitask to package.json since both IController and IDataProvider uses it.</p>
<p>Here’s the DataController:</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Text;
using com.core.data;
using com.core.initializer;
using Cysharp.Threading.Tasks;
using UnityEngine;

namespace com.core.data
{
    public class DataController : IController
    {
        private const string PLAYER_VERSION_KEY = "player-version-key";

        private IDataProvider _provider;

        public bool IsInitialized { get; private set; }

        public UniTask Initialize()
        {
            _provider = new LocalDataProvider();
            SaveUserVersion();
            IsInitialized = true;
            return UniTask.CompletedTask;
        }

        private void SaveUserVersion()
        {
            var versionHistory = Load(PLAYER_VERSION_KEY, new List&lt;string&gt;());
            var sb             = new StringBuilder();
            versionHistory.ForEach(vh =&gt; sb.Append(vh + Environment.NewLine));
            Debug.Log($"[DataController] Player version history: {sb}");

            if (!versionHistory.Contains(Application.version))
            {
                Debug.Log($"[DataController] Player's current version: {Application.version}");
                versionHistory.Add(Application.version);
                Save(PLAYER_VERSION_KEY, versionHistory);
            }
        }

        public void Save&lt;T&gt;(string key, T data) =&gt; _provider.Save(key, data);

        public T Load&lt;T&gt;(string key, T defaultValue = default) =&gt; _provider.Load(key, defaultValue);

        public bool         HasKey(string key)  =&gt; _provider.HasKey(key);
        public string[]     GetKeys()           =&gt; _provider.GetKeys();
        public UniTask      Delete(string key)  =&gt; _provider.Delete(key);
        public UniTask      DeleteAll()         =&gt; _provider.DeleteAll();
        public List&lt;string&gt; GetVersionHistory() =&gt; Load(PLAYER_VERSION_KEY, new List&lt;string&gt;());
    }
}
</code></pre>
<p>The controller delegates all logic to LocalDataProvider, which uses MemoryPack to serialize and write bytes to a "Data" folder under <code>Application.persistentDataPath</code>. The controller also keeps the user's app version history, which is useful for upgrade prompts or blocking old versions.</p>
<p>Here’s the full implementation:</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Cysharp.Threading.Tasks;
using MemoryPack;
using UnityEngine;

namespace com.core.data
{
    public class LocalDataProvider : IDataProvider
    {
        private const    string StorageFolderName = "Data";
        private readonly string _storagePath;

        private static readonly UTF8Encoding KeyEncoding = new(false);

        public bool IsInitialized =&gt; true;

        public LocalDataProvider()
        {
            _storagePath = Path.Combine(Application.persistentDataPath, StorageFolderName);
            EnsureStorageDirectoryExists();
        }

        public void Save&lt;T&gt;(string key, T data)
        {
            if (string.IsNullOrEmpty(key)) { Debug.LogWarning("[LocalDataProvider] Save called with null or empty key."); return; }
            if (data == null) { Debug.LogWarning("[LocalDataProvider] Save called with null data."); Delete(key).Forget(); return; }
            try
            {
                byte[] bin = MemoryPackSerializer.Serialize(data);
                WriteBytes(key, bin);
            }
            catch (Exception ex) { Debug.LogError($"[LocalDataProvider] Save failed for key '{key}': {ex.Message}"); throw; }
        }

        public T Load&lt;T&gt;(string key, T defaultValue = default)
        {
            if (string.IsNullOrEmpty(key)) { Debug.LogWarning("[LocalDataProvider] Load called with null or empty key."); return defaultValue; }
            if (!ReadBytes(key, out byte[] bin)) return defaultValue;
            try { return MemoryPackSerializer.Deserialize&lt;T&gt;(bin) ?? defaultValue; }
            catch (Exception ex) { Debug.LogError($"[LocalDataProvider] Load failed for key '{key}': {ex.Message}"); return defaultValue; }
        }

        public bool HasKey(string key) =&gt; !string.IsNullOrEmpty(key) &amp;&amp; File.Exists(GetFilePath(key));

        public UniTask Delete(string key)
        {
            if (string.IsNullOrEmpty(key)) return UniTask.CompletedTask;
            try { var filePath = GetFilePath(key); if (File.Exists(filePath)) File.Delete(filePath); }
            catch (Exception ex) { Debug.LogError($"[LocalDataProvider] Delete failed for key '{key}': {ex.Message}"); }
            return UniTask.CompletedTask;
        }

        public UniTask DeleteAll()
        {
            try
            {
                if (!Directory.Exists(_storagePath)) return UniTask.CompletedTask;
                foreach (string file in Directory.GetFiles(_storagePath))
                {
                    try { File.Delete(file); }
                    catch (Exception ex) { Debug.LogWarning($"[LocalDataProvider] Could not delete file '{file}': {ex.Message}"); }
                }
            }
            catch (Exception ex) { Debug.LogError($"[LocalDataProvider] DeleteAll failed: {ex.Message}"); }
            return UniTask.CompletedTask;
        }

        public string[] GetKeys()
        {
            if (!Directory.Exists(_storagePath)) return Array.Empty&lt;string&gt;();
            var keys = new List&lt;string&gt;();
            foreach (string file in Directory.GetFiles(_storagePath))
            {
                try { string key = DecodeKeyFromFileName(Path.GetFileName(file)); if (key != null) keys.Add(key); }
                catch { Debug.LogWarning($"[LocalDataProvider] Could not read file '{file}'."); }
            }
            return keys.ToArray();
        }

        private void EnsureStorageDirectoryExists() { if (!Directory.Exists(_storagePath)) Directory.CreateDirectory(_storagePath); }
        private void WriteBytes(string key, byte[] bin) { EnsureStorageDirectoryExists(); File.WriteAllBytes(GetFilePath(key), bin); }
        private bool ReadBytes(string key, out byte[] bin) { string filePath = GetFilePath(key); if (!File.Exists(filePath)) { bin = null; return false; } bin = File.ReadAllBytes(filePath); return true; }
        private string GetFilePath(string key) =&gt; Path.Combine(_storagePath, EncodeKeyToFileName(key));
        private static string EncodeKeyToFileName(string key) { byte[] bytes = KeyEncoding.GetBytes(key); string base64 = Convert.ToBase64String(bytes); return base64.Replace('+', '-').Replace('/', '_'); }
        private static string DecodeKeyFromFileName(string fileName) { try { string base64 = fileName.Replace('-', '+').Replace('_', '/'); return KeyEncoding.GetString(Convert.FromBase64String(base64)); } catch { return null; } }
    }
}
</code></pre>
<p>You can implement another IDataProvider (for example JSON via <a href="https://openupm.com/packages/com.newtonsoft.json/">Newtonsoft</a> or <a href="https://docs.unity3d.com/6000.3/Documentation/PlayerPrefs.html">PlayerPrefs</a>) and swap it in your DataController.</p>
<p>In production, you might use a local and a cloud provider and sync data based on the player's online status. The com.core.data <a href="https://github.com/TalhaCagatay/com.core.data">GitHub repo</a> may be updated with cloud saving and syncing. You can open an issue if you need that feature.</p>
<h2 id="heading-package-3-comcoredotween"><strong>Package 3: com.core.dotween</strong></h2>
<p>com.core.dotween is a Unity package wrapper around <a href="https://dotween.demigiant.com/">DOTween</a> (Demigiant). DoTween is a widely used, production-ready tween engine. The UI package uses it for popup show/hide animations.</p>
<p>DOTween is not available on OpenUPM, so you’ll typically need to download it from the <a href="https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676">Unity Asset Store</a> and import it into your project (for example, under Assets/Plugins).</p>
<p>Then you’ll run the DOTween setup window(it should pop automatically after importing) and click Create ASMDEF so assembly definition files are generated and you can reference them from other packages.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/698d2f3c217bebae73c3f5e8/1d2a1ea1-1cc4-4bc0-95b8-5e23d22d3f17.png" alt="1d2a1ea1-1cc4-4bc0-95b8-5e23d22d3f17" width="547" height="632" loading="lazy">

<p>Next, create a new package (for example, com.core.dotween) and move the Demigiant folder from Assets/Plugins into the package folder so that com.core.ui (or any other package) can depend on com.core.dotween via Package Manager or Git.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771252964839/36d9e2f0-31a1-445f-b536-8560d0987131.png" alt="Dotween package folders and files" width="221" height="167" loading="lazy">

<p>After that, reference com.core.dotween in com.core.ui's asmdef(You will create the UI package right after this) so you can use <code>DG.Tweening</code> namespace in BasePopup and other UI scripts.</p>
<p>com.core.dotween has no external dependencies – it only wraps the DOTween asset.</p>
<h2 id="heading-package-4-the-ui-package">Package 4: The UI Package</h2>
<p>com.core.ui centralizes how you show popups and full-screen UIs. It contains:</p>
<ul>
<li><p><strong>Popups</strong> – Modal or non-modal dialogs (confirm/cancel, alerts, forms) with a consistent API so you don’t duplicate panel logic in every screen. Popups are stacked – the top one is closed first.</p>
</li>
<li><p><strong>Screens</strong> – Full-screen panels (for example, loading, main menu). Only one screen is active at a time, and switching a screen hides the current one and shows the new one.</p>
</li>
</ul>
<p>Create a new package named com.core.ui with a structure such as:</p>
<ul>
<li><p><strong>Runtime/Interface/</strong> – <code>IUI</code></p>
</li>
<li><p><strong>Runtime/UIs/</strong> – <code>BasePopup</code>, <code>BaseScreen</code></p>
</li>
<li><p><strong>Runtime/</strong> – <code>UIController</code>, <code>UIParent</code></p>
</li>
<li><p><strong>Runtime/Resources/UIPrefabs/</strong> – <code>UIParent</code> prefab, and subfolders Popups and Screens</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771254115546/a71fd415-901c-472c-b46b-f919b5e6ec82.png" alt="UI package folders and files" width="353" height="649" loading="lazy">

<p>Add com.core.dotween, com.core.initializer, and com.cysharp.unitask as dependencies in package.json and asmdef.</p>
<p>Popups work like a stack: each popup is shown on top of the previous one and closed from top to bottom. Screens are single-active: only one screen is visible at a time. UIController hides the current one when you show another. UIController is the single point of contact for both screens and popups and handles stacking, caching, and background placement.</p>
<h3 id="heading-iui-interface">IUI Interface</h3>
<p>Both BasePopup and BaseScreen implement IUI:</p>
<pre><code class="language-csharp">using System;
using Cysharp.Threading.Tasks;

namespace com.core.ui
{
    public interface IUI
    {
        event Action&lt;IUI&gt; Showed;
        event Action&lt;IUI&gt; Hidden;

        UniTask ShowAsync();
        UniTask HideAsync();
    }
}
</code></pre>
<p>IUI is a very basic interface with 2 async Show/Hide methods and 2 events to be fired upon completion of those methods.</p>
<h3 id="heading-basepopup">BasePopup</h3>
<p>BasePopup uses DoTween to animate scale on show/hide and exposes events and overridable animation methods:</p>
<pre><code class="language-csharp">using System;
using Cysharp.Threading.Tasks;
using DG.Tweening;
using UnityEngine;

namespace com.core.ui
{
    public abstract class BasePopup : MonoBehaviour, IUI
    {
        public event Action&lt;IUI&gt; StartedShowing;
        public event Action&lt;IUI&gt; Showed;
        public event Action&lt;IUI&gt; Hidden;

        [SerializeField] private float   openingTime  = 0.35f;
        [SerializeField] private float   closingTime  = 0.25f;
        [SerializeField] private Vector3 initialScale = new(0.75f, 0.75f, 0.75f);
        [SerializeField] private Ease   openingEase  = Ease.OutBack;
        [SerializeField] private Ease   closingEase  = Ease.InBack;

        protected virtual Tweener PlayShowAnimation(Action completedCallback) =&gt; transform.DOScale(Vector3.one, openingTime).SetEase(openingEase).SetUpdate(true).OnComplete(() =&gt; completedCallback?.Invoke());
        protected virtual Tweener PlayHideAnimation(Action completedCallback) =&gt; transform.DOScale(initialScale, closingTime).SetEase(closingEase).SetUpdate(true).OnComplete(() =&gt; completedCallback?.Invoke());

        public UniTask ShowAsync()
        {
            StartedShowing?.Invoke(this);
            transform.SetAsLastSibling();
            var utcs = new UniTaskCompletionSource();
            transform.localScale = initialScale;
            gameObject.SetActive(true);

            PlayShowAnimation(() =&gt; OnAnimationShowed(utcs));
            return utcs.Task;
        }

        public void Show() =&gt; ShowAsync().Forget();

        public UniTask HideAsync()
        {
            var utcs = new UniTaskCompletionSource();
            PlayHideAnimation(() =&gt; OnAnimationCompleted(utcs));
            return utcs.Task;
        }

        private void OnAnimationShowed(UniTaskCompletionSource utcs)
        {
            Showed?.Invoke(this);
            utcs.TrySetResult();
        }

        private void OnAnimationCompleted(UniTaskCompletionSource utcs)
        {
            transform.SetAsFirstSibling();
            gameObject.SetActive(false);
            Hidden?.Invoke(this);
            utcs.TrySetResult();
        }

        public void Hide() =&gt; HideAsync().Forget();
    }
}
</code></pre>
<p>You can see that DoTween is the core component in this class and a lot of parameters are configurable like opening/closing times and easings. Notice how DoTween completion callbacks are utilized to fire Showed and Hidden events.</p>
<p>Another important thing here is the usage of SetUpdate(true) for animations. This makes animations to ignore timescale. I found that most of the time it's best to ignore the timescale for animations but if you don't want this then feel free to change it.</p>
<h3 id="heading-basescreen"><strong>BaseScreen</strong></h3>
<p>BaseScreen only enables/disables the GameObject and raises events. There’s no animation:</p>
<pre><code class="language-csharp">using System;
using Cysharp.Threading.Tasks;
using UnityEngine;

namespace com.core.ui
{
    public abstract class BaseScreen : MonoBehaviour, IUI
    {
        public event Action&lt;IUI&gt; Showed;
        public event Action&lt;IUI&gt; Hidden;

        public virtual UniTask ShowAsync()
        {
            gameObject.SetActive(true);
            Showed?.Invoke(this);
            return UniTask.CompletedTask;
        }

        public UniTask HideAsync()
        {
            gameObject.SetActive(false);
            Hidden?.Invoke(this);
            return UniTask.CompletedTask;
        }
    }
}
</code></pre>
<p>You will notice that BaseScreen doesn't need UniTask since it is not performing any async operations but it is still beneficial to have this since it doesn't cause any overheads and if we ever need an animation for any of our screens like popups, we have it ready.</p>
<h3 id="heading-uicontroller"><strong>UIController</strong></h3>
<p>UIController implements <code>IController</code>, instantiates UIParent from Resources, and provides APIs to push/pop popups and show/hide screens. It caches popup and screen instances by type and loads prefabs from Resources:</p>
<ul>
<li><p><strong>UIParent</strong>: <code>Resources/UIPrefabs/UIParent</code></p>
</li>
<li><p><strong>Popups</strong>: <code>Resources/UIPrefabs/Popups/&lt;TypeName&gt;.prefab</code></p>
</li>
<li><p><strong>Screens</strong>: <code>Resources/UIPrefabs/Screens/&lt;TypeName&gt;.prefab</code></p>
</li>
</ul>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using com.core.initializer;
using Cysharp.Threading.Tasks;
using UnityEngine;
using Object = UnityEngine.Object;

namespace com.core.ui
{
    public class UIController : IController
    {
        private const string UI_PARENT_PATH    = "UIPrefabs/UIParent";
        private const string POPUPS_RESOURCES  = "UIPrefabs/Popups";
        private const string SCREENS_RESOURCES = "UIPrefabs/Screens";

        private readonly Stack&lt;BasePopup&gt;             _popupStack  = new();
        private readonly Dictionary&lt;Type, BasePopup&gt;  _popupCache  = new();
        private readonly Dictionary&lt;Type, BaseScreen&gt; _ScreenCache = new();

        private BaseScreen _currentScreen;
        private UIParent   _uiParent;

        public bool IsInitialized { get; private set; }

        public UniTask Initialize()
        {
            var uiParentPrefab = Resources.Load&lt;UIParent&gt;(UI_PARENT_PATH);
            if (uiParentPrefab == null)
            {
                Debug.LogError($"[UIController] UIParent prefab not found at {UI_PARENT_PATH}. Ensure it exists in a Resources folder.");
                return UniTask.CompletedTask;
            }

            _uiParent      = Object.Instantiate(uiParentPrefab);
            _uiParent.name = "UIParent";

            Object.DontDestroyOnLoad(_uiParent.gameObject);

            IsInitialized = true;
            return UniTask.CompletedTask;
        }

        public async UniTask&lt;TPopup&gt; PushPopupAsync&lt;TPopup&gt;() where TPopup : BasePopup
        {
            var popup = GetOrCreatePopup&lt;TPopup&gt;();
            _popupStack.Push(popup);
            var popupTask = popup.ShowAsync();
            UpdateBackgroundForTopPopup();
            await popupTask;
            return popup;
        }

        public void PushPopup&lt;TPopup&gt;() where TPopup : BasePopup =&gt; PushPopupAsync&lt;TPopup&gt;().Forget();

        public async UniTask PopPopupAsync()
        {
            if (_popupStack.Count == 0)
            {
                Debug.LogWarning("[UIController] PopPopup called but popup stack is empty.");
                return;
            }

            var top = _popupStack.Pop();
            await top.HideAsync();
            UpdateBackgroundForTopPopup();
        }

        public void PopPopup() =&gt; PopPopupAsync().Forget();

        public BasePopup PeekPopup() =&gt; _popupStack.Count &gt; 0 ? _popupStack.Peek() : null;

        public async UniTask&lt;TScreen&gt; ShowScreenAsync&lt;TScreen&gt;() where TScreen : BaseScreen
        {
            var screen = GetOrCreateScreen&lt;TScreen&gt;();

            if (_currentScreen == screen &amp;&amp; screen.gameObject.activeSelf) return screen;
            if (_currentScreen != null   &amp;&amp; _currentScreen != screen &amp;&amp; _currentScreen.gameObject.activeSelf) await _currentScreen.HideAsync();

            _currentScreen = screen;
            await screen.ShowAsync();
            return screen;
        }

        public async UniTask HideScreenAsync&lt;TScreen&gt;() where TScreen : BaseScreen
        {
            var type = typeof(TScreen);
            if (!_ScreenCache.TryGetValue(type, out var screen))
            {
                Debug.LogWarning($"[UIController] HideScreenAsync&lt;{type.Name}&gt; called but Screen was never shown (not in cache).");
                return;
            }

            await screen.HideAsync();

            if (_currentScreen == screen) _currentScreen = null;
        }

        public void ShowScreen&lt;TScreen&gt;() where TScreen : BaseScreen =&gt; ShowScreenAsync&lt;TScreen&gt;().Forget();
        public void HideScreen&lt;TScreen&gt;() where TScreen : BaseScreen =&gt; HideScreenAsync&lt;TScreen&gt;().Forget();

        private TPopup GetOrCreatePopup&lt;TPopup&gt;() where TPopup : BasePopup
        {
            var type = typeof(TPopup);
            if (_popupCache.TryGetValue(type, out var cached) &amp;&amp; cached != null) return (TPopup)cached;

            var prefab = LoadPopupPrefab&lt;TPopup&gt;();
            if (prefab == null)
            {
                Debug.LogError($"[UIController] Popup prefab for {type.Name} not found at {POPUPS_RESOURCES}/{type.Name}. Ensure the prefab exists in a Resources folder.");
                return null;
            }

            var instance = UnityEngine.Object.Instantiate(prefab, _uiParent.PopupParent);
            instance.gameObject.SetActive(false);

            var popup = instance.GetComponent&lt;TPopup&gt;();
            _popupCache[type] = popup;

            return popup;
        }

        private TScreen GetOrCreateScreen&lt;TScreen&gt;() where TScreen : BaseScreen
        {
            var type = typeof(TScreen);
            if (_ScreenCache.TryGetValue(type, out var cached) &amp;&amp; cached != null) return (TScreen)cached;

            var prefab = LoadScreenPrefab&lt;TScreen&gt;();
            if (prefab == null)
            {
                Debug.LogError($"[UIController] Screen prefab for {type.Name} not found at {SCREENS_RESOURCES}/{type.Name}. Ensure the prefab exists in a Resources folder.");
                return null;
            }

            var instance = UnityEngine.Object.Instantiate(prefab, _uiParent.ScreenParent);
            instance.gameObject.SetActive(false);

            var screen = instance.GetComponent&lt;TScreen&gt;();
            _ScreenCache[type] = screen;

            return screen;
        }

        private TPopup  LoadPopupPrefab&lt;TPopup&gt;() where TPopup : BasePopup     =&gt; LoadViewPrefab&lt;TPopup&gt;(POPUPS_RESOURCES);
        private TScreen LoadScreenPrefab&lt;TScreen&gt;() where TScreen : BaseScreen =&gt; LoadViewPrefab&lt;TScreen&gt;(SCREENS_RESOURCES);

        private static T LoadViewPrefab&lt;T&gt;(string resourcesPath) where T : MonoBehaviour
        {
            var type = typeof(T);
            var path = $"{resourcesPath}/{type.Name}";
            var go   = Resources.Load&lt;GameObject&gt;(path);
            return go != null ? go.GetComponent&lt;T&gt;() : null;
        }

        private void UpdateBackgroundForTopPopup()
        {
            var backgroundGO = _uiParent.BackgroundGO;
            if (backgroundGO == null) return;

            if (_popupStack.Count &gt; 0)
            {
                var topPopup = _popupStack.Peek();
                if (topPopup != null &amp;&amp; topPopup.gameObject.activeSelf)
                {
                    // Position background one step behind the top popup
                    var topPopupIndex = topPopup.transform.GetSiblingIndex();
                    backgroundGO.SetActive(true);
                    backgroundGO.transform.SetSiblingIndex(Mathf.Max(0, topPopupIndex - 1));
                }
                else
                {
                    // Top popup is inactive, hide background
                    backgroundGO.SetActive(false);
                }
            }
            else
            {
                // No popups in stack, hide background
                backgroundGO.SetActive(false);
            }
        }
    }
}
</code></pre>
<p>Usage:</p>
<pre><code class="language-csharp">var ui = ControllerHandler.GetController&lt;UIController&gt;();
await ui.PushPopupAsync&lt;MyPopup&gt;();
await ui.PopPopupAsync();
await ui.ShowScreenAsync&lt;MainMenuScreen&gt;();
await ui.HideScreenAsync&lt;LoadingScreen&gt;();
</code></pre>
<p>UIController also updates the background GameObject so it indexes behind the top popup.</p>
<p>It uses <code>GetOrCreatePopup&lt;TPopup&gt;()</code> / <code>GetOrCreateScreen&lt;TScreen&gt;()</code> to load and cache prefabs from <code>Resources/UIPrefabs/Popups/&lt;TypeName&gt;</code> and <code>Resources/UIPrefabs/Screens/&lt;TypeName&gt;</code>, pushes popups onto a stack, and shows/hides screens with async methods.</p>
<p>UIParent is a MonoBehaviour that holds references to ScreenParent, PopupParent, and BackgroundGO:</p>
<pre><code class="language-csharp">using UnityEngine;

namespace com.core.ui
{
    public class UIParent : MonoBehaviour
    {
        [SerializeField] private Transform  screensParent;
        [SerializeField] private Transform  popupsParent;
        [SerializeField] private GameObject backgroundGO;

        public Transform  ScreenParent =&gt; screensParent;
        public Transform  PopupParent  =&gt; popupsParent;
        public GameObject BackgroundGO =&gt; backgroundGO;
    }
}
</code></pre>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771288099657/6104e31e-e8e0-489c-bca5-592d5daec174.png" alt="UIParent prefab hierarchy" width="360" height="230" loading="lazy">

<p>UIParent prefab has a canvas and UIParent script attached:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/698d2f3c217bebae73c3f5e8/cb79381a-35c3-49ac-af50-da33b0f7f988.png" alt="UIParent prefab components" style="display:block;margin:0 auto" width="1243" height="1444" loading="lazy">

<p>There are a couple limitations here as well. First, popups and screens must live under Resources/UIPrefabs/Popups and Resources/UIPrefabs/Screens. Second, prefab name must match the script/type name (for example, TestPopup prefab name for a script named TestPopup).</p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<p>In this article, you set up a Unity project and walked through creating four reusable packages:</p>
<ul>
<li><p><strong>com.core.initializer</strong> – You created the package, added <strong>UniTask</strong>, defined <code>IController</code>, used the <code>Creator</code> helper to find and create controllers (including MonoBehaviours), and implemented <code>ControllerHandler</code> to run initialization at <code>BeforeSceneLoad</code> and expose controllers via <code>GetController&lt;T&gt;()</code>.</p>
</li>
<li><p><strong>com.core.data</strong> – You use <code>IDataProvider</code> and <code>LocalDataProvider</code> with MemoryPack for binary local save/load, and the <code>DataController</code> that implements <code>IController</code> and tracks version history.</p>
</li>
<li><p><strong>com.core.dotween</strong> – You wrap the <strong>DoTween</strong> asset as a package so other packages (like <strong>com.core.ui</strong>) can reference it for animations.</p>
</li>
<li><p><strong>com.core.ui</strong> – You created a modular UI package that you can use in your games to handle popups and full size screens. You can also extend this to add other UI types in the future.</p>
</li>
</ul>
<p>Building these as separate packages keeps your code modular and speeds up development across projects. You can install each package via Git into any Unity project.</p>
<p>Example manifest.json file to implement these packages:</p>
<pre><code class="language-json">{
  "dependencies"    : {
	"com.core.data"       : "https://github.com/TalhaCagatay/com.core.data.git#v0.1.0",
	"com.core.initializer": "https://github.com/TalhaCagatay/com.core.initializer.git#v0.1.0",
	"com.core.dotween"    : "https://github.com/TalhaCagatay/com.core.dotween.git#v0.1.0",
	"com.core.ui"         : "https://github.com/TalhaCagatay/com.core.ui.git#v0.1.0"
  },
  "scopedRegistries": [
	{
	  "name"  : "package.openupm.com",
	  "url"   : "https://package.openupm.com",
	  "scopes": [
		"com.cysharp.unitask",
		"com.cysharp.memorypack"
	  ]
	}
  ]
}
</code></pre>
<p><strong>Resources:</strong></p>
<ul>
<li><p>com.core.initializer on <a href="https://github.com/TalhaCagatay/com.core.initializer">GitHub</a></p>
</li>
<li><p>com.core.data on <a href="https://github.com/TalhaCagatay/com.core.data">GitHub</a></p>
</li>
<li><p>com.core.dotween on <a href="https://github.com/TalhaCagatay/com.core.dotween">Github</a></p>
</li>
<li><p>com.core.ui on <a href="https://github.com/TalhaCagatay/com.core.ui">Github</a></p>
</li>
<li><p><a href="https://play.google.com/store/apps/details?id=com.Focus.Matchingham">Example game</a> that I developed and used many modular systems like the ones you built in this article.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Type Safe Unions in C# With OneOf ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever needed a method to return different types depending on the situation? Perhaps a payment processor that returns different payment types, an order that can be in various states with different data, or better, a file loader that handles mu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-type-safe-unions-in-c-with-oneof/</link>
                <guid isPermaLink="false">6973f8cd15349392f17d3760</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Fri, 23 Jan 2026 22:40:13 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769193036631/70de89f6-047b-4894-9685-2c65c05b3620.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever needed a method to return different types depending on the situation? Perhaps a payment processor that returns different payment types, an order that can be in various states with different data, or better, a file loader that handles multiple formats?</p>
<p>In C#, we typically solve this with inheritance hierarchies, marker interfaces, or wrapper objects – all of which add complexity and reduce type safety. But luckily, there's a better way: discriminated unions using the OneOf library.</p>
<p>You may be familiar with union types if you’ve programmed with TypeScript before, as they’re one of the pivotal features of the language. Union types are not a concept which can be found natively within C#, but they are planned for a future release. Until then, you can use the <code>OneOf&lt;T1,T2..&gt;</code> library.</p>
<p>In this article, I'll show you how <code>OneOf</code> brings F#-like discriminated unions to C#, enabling you to write cleaner, more expressive, and type-safe code across a variety of scenarios – from polymorphic return types to state machines, even elegant error handling.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-oneof">What is OneOf?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-installing-oneof">Installing OneOf</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-concepts">Core Concepts</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-real-world-use-cases">Real-World Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-other-use-cases">Other Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-benefits-of-oneof">Key Benefits of OneOf</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-oneof">What is OneOf?</h2>
<p>The OneOf package offers discriminated unions for C#, allowing you to return one of several predefined types from a single method. Unlike a <code>Tuple</code>, which bundles multiple values together (A <strong>and</strong> B), OneOf represents a choice (A <strong>or</strong> B <strong>or</strong> C).</p>
<p>Think of it as a type-safe way to say: "This method returns either type A, <strong>or</strong> type B, <strong>or</strong> type C" – and the compiler enforces that you handle all possibilities.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Instead of this (returns both, whether you need them or not)</span>
<span class="hljs-keyword">public</span> (User user, Error error) GetUser(<span class="hljs-keyword">int</span> id) { ...  }

<span class="hljs-comment">// You can do this (returns one OR the other)</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> OneOf&lt;User, NotFound, DatabaseError&gt; <span class="hljs-title">GetUser</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> id</span>)</span> { ... }
</code></pre>
<h3 id="heading-why-oneof-matters">Why OneOf Matters</h3>
<ul>
<li><p><strong>Type safety</strong>: The compiler ensures you handle every possible return type</p>
</li>
<li><p><strong>Self-documenting</strong>: Method signatures clearly show all possible outcomes</p>
</li>
<li><p><strong>No inheritance required</strong>: Returns different types without forcing them into a class hierarchy</p>
</li>
<li><p><strong>Pattern matching</strong>: Uses <code>.Match()</code> to handle each case exhaustively</p>
</li>
<li><p><strong>Flexibility</strong>: Supports 2, 3, 4+ different return types as needed</p>
</li>
</ul>
<h2 id="heading-installing-oneof">Installing OneOf</h2>
<h3 id="heading-option-1-recommended">Option 1 (Recommended):</h3>
<p>Using the terminal, navigate to your project folder and run the below command:</p>
<pre><code class="lang-bash">dotnet add package OneOf
</code></pre>
<h3 id="heading-option-2">Option 2:</h3>
<p>Using your IDE (Visual Studio, Rider, or VS Code):</p>
<ol>
<li><p>Right-click your project file</p>
</li>
<li><p>Select "Manage NuGet Packages"</p>
</li>
<li><p>Search for "OneOf"</p>
</li>
<li><p>Click Install</p>
</li>
</ol>
<h2 id="heading-core-concepts-and-functionality">Core Concepts And Functionality</h2>
<p>There are multiple core concepts you’ll need to understand to get the most out of the OneOf library and understand its real benefits. These are:</p>
<h3 id="heading-union-types-one-of-many">Union Types: One of Many</h3>
<p>At its heart, OneOf represents a union type. A value that can be one of several predefined types at any given time. Think of it as a type-safe container that holds exactly one value, but that value could be any of the types you specify.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// This variable can hold a string OR an int OR a bool</span>
<span class="hljs-comment">// but only ONE at a time</span>
OneOf&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">bool</span>&gt; myValue;

myValue = <span class="hljs-string">"hello"</span>;     <span class="hljs-comment">// Currently holds a string</span>
myValue = <span class="hljs-number">42</span>;          <span class="hljs-comment">// Now holds an int</span>
myValue = <span class="hljs-literal">true</span>;        <span class="hljs-comment">// Now holds a bool</span>
</code></pre>
<p>This is fundamentally different from a C# <code>Tuple</code> type, which holds multiple values simultaneously:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Tuple: Holds ALL values at once (AND) </span>
<span class="hljs-keyword">var</span> tuple = (<span class="hljs-string">"hello"</span>, <span class="hljs-number">42</span>, <span class="hljs-literal">true</span>); <span class="hljs-comment">// Has string AND int AND bool</span>

<span class="hljs-comment">// OneOf: Holds ONE value at a time (OR) </span>
OneOf&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">bool</span>&gt; union = <span class="hljs-string">"hello"</span>; <span class="hljs-comment">// Has string OR int OR bool</span>
</code></pre>
<h3 id="heading-type-safety-and-exhaustive-handling">Type Safety and Exhaustive Handling</h3>
<p>OneOf isn't just convenient, it's compiler-enforced. When you work with a OneOf value, the compiler ensures that you handle every possible type within your <code>.Match()</code> method. This eliminates entire categories of bugs where you forget to handle a case.</p>
<p>For example:</p>
<pre><code class="lang-csharp">OneOf&lt;Success, Failure, Pending&gt; result = GetResult();

<span class="hljs-comment">// Compiler forces you to handle all three</span>
result.Match(
    success =&gt; HandleSuccess(success),
    failure =&gt; HandleFailure(failure),
);

<span class="hljs-comment">// Missing a case? Won't compile!</span>
</code></pre>
<p>You’ll get a compiler warning and if you hover over it in your IDE or code editor, you’ll see a hint like so:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769177846621/88d52e4b-3e8b-4e1b-8e2c-4eba36c6d24d.png" alt="Image showing intellisense hints, informing the developer that they have missed a handler function, based on 3 types specified and only 2 handlers" class="image--center mx-auto" width="1106" height="648" loading="lazy"></p>
<h3 id="heading-the-match-method">The <code>.Match()</code> Method</h3>
<p>The <code>.Match()</code> method is one of OneOf's killer features. It requires you to provide a handler function for each possible type in your union, ensuring you never forget to handle a case.</p>
<p>Think of it like a type-safe switch statement that the compiler enforces:</p>
<pre><code class="lang-csharp">OneOf&lt;CreditCardInfo,PayPalUser,CryptoAccount&gt; result = GetPaymentMethod(); <span class="hljs-comment">// MasterCard</span>

result.Match(
    creditCard =&gt; ProcessCreditCard(creditCard),
    paypal =&gt; ProcessPayPal(paypal),
    crypto =&gt; ProcessCrypto(crypto)
);
</code></pre>
<p><strong>How .Match() works:</strong></p>
<ol>
<li><p>OneOf determines which type the value currently holds</p>
</li>
<li><p>It executes the corresponding handler function for that type</p>
</li>
<li><p>It passes the actual value (with the correct type) to your handler</p>
</li>
<li><p>It returns the result from whichever handler executed</p>
</li>
</ol>
<p>The generic type ordering matters, especially in relation to the <code>.Match()</code> method and the defined handlers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769194375840/9832db95-6d04-4cc0-9376-751cb4e50138.png" alt="code block showing order of return types, CreditCard, Paypal and CryptoWallet, combined with the .Match method to define each handler for each type." class="image--center mx-auto" width="1502" height="540" loading="lazy"></p>
<ul>
<li><p><strong>Generic typing order:</strong> If you declare <code>OneOf&lt;CreditCard, PayPal, CryptoWallet&gt;</code>, then <code>CreditCard</code> is <code>T0</code>, <code>PayPal</code> is <code>T1,</code> and <code>CryptoWallet</code> is <code>T2</code>. That order determines which handler in <code>.Match(...)</code> will be executed, not its type.</p>
</li>
<li><p><strong>Handler parameter names are arbitrary</strong>: You can name them <code>option1</code>, <code>foo</code>, or <code>creditCard</code>. The name doesn’t determine the type, position does. The compiler binds the first handler to <code>CreditCard</code>, the second to <code>PayPal</code>, and third to CryptoWallet.</p>
</li>
<li><p>Each handler receives a strongly-typed parameter corresponding to its position. When the first handler runs, its parameter is a <code>CreditCard</code> object (with full IntelliSense and compile-time checks).</p>
</li>
<li><p>For readability, prefer meaningful names (for example, <code>creditCard</code>, <code>payPal</code>, <code>crypto</code>) rather than <code>option1/2/3</code>, as this was only for demonstration purposes.</p>
</li>
</ul>
<h3 id="heading-accessing-values">Accessing Values</h3>
<p>While <code>.Match()</code> is the recommended approach, OneOf also provides direct type checking and access, albeit quite cumbersome and not as intuitive.</p>
<pre><code class="lang-csharp">OneOf&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">int</span>&gt; example = <span class="hljs-string">"hello"</span>;

<span class="hljs-comment">// Check which type it contains</span>
<span class="hljs-keyword">if</span> (example.IsT0)  <span class="hljs-comment">// Is it the first type (string)?</span>
{
    <span class="hljs-keyword">string</span> str = example.AsT0;  <span class="hljs-comment">// Get it as a string</span>
    Console.WriteLine(str);
}
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (example.IsT1)  <span class="hljs-comment">// Is it the second type (int)?</span>
{
    <span class="hljs-keyword">int</span> num = example.AsT1;  <span class="hljs-comment">// Get it as an int</span>
    Console.WriteLine(num);
}
</code></pre>
<p>You should avoid this approach in most cases for several reasons:</p>
<p>Firstly, you lose the compiler enforcement that makes <code>.Match()</code> so powerful. Want to add a third type later? The compiler won't remind you to handle it here, and your code could become brittle and be more prone to failure.</p>
<p>Secondly, it's verbose and cluttered. Instead of one clean <code>.Match()</code> call, you need multiple if-else blocks that make your code harder to read and maintain.</p>
<p>Thirdly, the <code>T0</code>, <code>T1</code>, <code>T2</code> naming convention is positional and confusing. Which type was <code>T0</code> again? You have to constantly refer back to the method signature to remember the order, which can become frustrating for yourself and development team.</p>
<p>Finally, it's error-prone. Nothing prevents you from forgetting to check <code>IsT2</code> when dealing with three or more types.</p>
<p>Use <code>.Match()</code> whenever possible. Only resort to <code>IsT0</code>/<code>AsT0</code> when you have a specific reason to check for just one type, and the others are irrelevant in the current code flow.</p>
<h2 id="heading-a-solution-to-exception-driven-control-flow">A Solution to Exception-Driven Control Flow</h2>
<p>Many codebases overuse exceptions for control flow, making code harder to follow and debug. When you see a method call, there's no indication in the signature whether it might throw an exception or what type of errors to expect. This leads to several issues:</p>
<h3 id="heading-hidden-control-flow">Hidden Control Flow:</h3>
<pre><code class="lang-csharp"><span class="hljs-comment">// What can go wrong here? The signature doesn't tell you.</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">GetUser</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> id</span>)</span>
{
    <span class="hljs-keyword">var</span> user = _dbContext.Users.Find(id);
    <span class="hljs-keyword">if</span> (user == <span class="hljs-literal">null</span>)
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UserNotFoundException();  <span class="hljs-comment">// Hidden jump in control flow!</span>

    <span class="hljs-keyword">return</span> user;
}

<span class="hljs-comment">// Caller has no idea this can throw an exception</span>
<span class="hljs-keyword">var</span> user = _userService.GetUser(<span class="hljs-number">123</span>);  <span class="hljs-comment">// Might explode!</span>
Console.WriteLine(user.Name);
</code></pre>
<h3 id="heading-exceptions-as-expected-outcomes">Exceptions As Expected Outcomes</h3>
<p>When a user enters an invalid email or a record isn't found, these aren't truly <em>exceptional</em> circumstances –they're expected, predictable outcomes that should be part of your normal business logic. Using exceptions for these scenarios treats routine validation as a crisis.</p>
<h3 id="heading-performance-impact-in-hot-paths">Performance Impact in Hot Paths</h3>
<p>While not always significant, throwing exceptions involves stack unwinding which can be hundreds of times slower than returning a value. In tight loops or high-throughput APIs, this overhead accumulates quickly.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Which exceptions should I catch? All of them? Specific ones?</span>
<span class="hljs-keyword">try</span>
{
    <span class="hljs-keyword">var</span> user = _userService.GetUser(id);
    <span class="hljs-keyword">var</span> order = _orderService.CreateOrder(user);
    <span class="hljs-keyword">var</span> payment = _paymentService.ProcessPayment(order);
}
<span class="hljs-keyword">catch</span> (Exception ex)  <span class="hljs-comment">// Too broad? Catching things we shouldn't?</span>
{
    <span class="hljs-comment">// Which operation failed? Hard to tell.</span>
    <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-string">"Something went wrong"</span>);
}
</code></pre>
<h2 id="heading-oneof-provides-a-cleaner-alternative">OneOf Provides a Cleaner Alternative</h2>
<p>OneOf makes failures explicit, type-safe, and part of the method signature. When you see a method that returns <code>OneOf&lt;Success&lt;T&gt;, Failure&gt;</code>, you immediately know:</p>
<ol>
<li><p>This method can fail</p>
</li>
<li><p>You must handle both success and failure cases</p>
</li>
<li><p>The compiler will enforce this</p>
</li>
</ol>
<p>The following code shows how to implement it:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define your result types</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Success</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">T Value</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Failure</span>(<span class="hljs-params">ErrorType Type, <span class="hljs-keyword">string</span>[] Messages</span>)</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">enum</span> ErrorType 
{
    Validation,
    NotFound,
    Database,
    Conflict,
}

<span class="hljs-comment">// The signature now TELLS you this can fail</span>
<span class="hljs-keyword">public</span> OneOf&lt;Success&lt;User&gt;, Failure&gt; GetUser(<span class="hljs-keyword">int</span> id)
{
    <span class="hljs-keyword">try</span>
    {
        <span class="hljs-keyword">var</span> user = _dbContext.Users.Find(id);

        <span class="hljs-keyword">if</span> (user == <span class="hljs-literal">null</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Failure(ErrorType.NotFound, <span class="hljs-keyword">new</span>[] { <span class="hljs-string">$"User <span class="hljs-subst">{id}</span> not found"</span> });

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Success&lt;User&gt;(user);
    }
    <span class="hljs-keyword">catch</span> (DbException ex)
    {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Failure(ErrorType.Database, <span class="hljs-keyword">new</span>[] { <span class="hljs-string">"Database error"</span>, ex.Message });
    }
}

<span class="hljs-comment">// Usage: Now the caller MUST handle both cases - compiler enforces it</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetUserEndpoint</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> id</span>)</span>
{
    <span class="hljs-keyword">var</span> result = _userService.GetUser(id);

    <span class="hljs-keyword">return</span> result.Match(
        success =&gt; Ok(success.Value),
        failure =&gt; failure.Type <span class="hljs-keyword">switch</span>
        {
            ErrorType.NotFound =&gt; NotFound(<span class="hljs-keyword">new</span> { errors = failure.Messages }),
            ErrorType.Database =&gt; StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { errors = failure.Messages }),
            ErrorType.Validation =&gt; BadRequest(<span class="hljs-keyword">new</span> { errors = failure.Messages }),
            ErrorType.Conflict =&gt; Conflict(<span class="hljs-keyword">new</span> { errors = failure.Messages }),
            _ =&gt; StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { errors = failure.Messages })
        }
    );
}
</code></pre>
<p>What makes this better?</p>
<ul>
<li><p><strong>It’s self-documenting</strong>: The method signature explicitly states "this returns a User OR a Failure" – no hidden surprises.</p>
</li>
<li><p><strong>There’s compiler-enforced handling</strong>: Forget to handle the failure case? Compilation error. The compiler won't let you ignore potential failures.</p>
</li>
<li><p><strong>There’s clear intent</strong>: When you call a method returning <code>OneOf&lt;Success&lt;T&gt;, Failure&gt;</code>, you know immediately you need to handle both paths. No guessing about which exceptions might be thrown.</p>
</li>
</ul>
<h2 id="heading-when-to-still-use-exceptions"><strong>When to Still Use Exceptions:</strong></h2>
<p>The goal isn't to eliminate exceptions entirely, but to reserve them for truly exceptional circumstances while using <code>OneOf</code> for predictable, business-logic failures. You could still use exceptions in these scenarios:</p>
<ul>
<li><p>Truly unexpected failures (out-of-memory, hardware failures)</p>
</li>
<li><p>Framework/library boundaries that expect exceptions</p>
</li>
<li><p>Constructor failures (constructors can't return Result types)</p>
</li>
<li><p>Third-party code contracts</p>
</li>
</ul>
<h2 id="heading-other-oneof-use-cases">Other OneOf Use Cases</h2>
<h3 id="heading-use-case-1-polymorphic-return-types-without-inheritance">Use Case 1: Polymorphic Return Types (Without Inheritance)</h3>
<p>When you need to return different types based on logic but don't want to force inheritance:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Different payment methods - no shared base class needed</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> OneOf&lt;CreditCardPayment, PayPalPayment, CryptoPayment&gt; <span class="hljs-title">GetPaymentMethod</span>(<span class="hljs-params">PaymentRequest request</span>)</span>
{
    <span class="hljs-keyword">return</span> request.Method <span class="hljs-keyword">switch</span>
    {
        <span class="hljs-string">"card"</span> =&gt; <span class="hljs-keyword">new</span> CreditCardPayment(request.CardNumber, request.CVV),
        <span class="hljs-string">"paypal"</span> =&gt; <span class="hljs-keyword">new</span> PayPalPayment(request.Email),
        <span class="hljs-string">"crypto"</span> =&gt; <span class="hljs-keyword">new</span> CryptoPayment(request.WalletAddress),
        _ =&gt; <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"Unknown payment method"</span>)
    };
}
<span class="hljs-comment">// Usage - compiler enforces handling all types</span>
<span class="hljs-keyword">var</span> payment = GetPaymentMethod(request);
payment.Match(
    card =&gt; ChargeCard(card),
    paypal =&gt; ProcessPayPal(paypal),
    crypto =&gt; ProcessCrypto(crypto)
);
</code></pre>
<p>Why this is better than inheritance:</p>
<ul>
<li><p>No artificial base class needed</p>
</li>
<li><p>Each payment type can have completely different properties</p>
</li>
<li><p>Clear, explicit handling of each case</p>
</li>
<li><p>Easy to add new payment types (compiler will tell you everywhere to update)</p>
</li>
</ul>
<h3 id="heading-use-case-2-state-machines-with-rich-data">Use Case 2: State Machines With Rich Data</h3>
<p>Representing different states in a workflow where each state carries different information:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Order</span>
{
    <span class="hljs-keyword">public</span> OneOf&lt;Pending, Processing, Shipped, Delivered, Cancelled&gt; Status { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Pending</span>(<span class="hljs-params">DateTime OrderedAt</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Processing</span>(<span class="hljs-params">DateTime StartedAt, <span class="hljs-keyword">string</span> WarehouseId</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Shipped</span>(<span class="hljs-params">DateTime ShippedAt, <span class="hljs-keyword">string</span> TrackingNumber, <span class="hljs-keyword">string</span> Carrier</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Delivered</span>(<span class="hljs-params">DateTime DeliveredAt, <span class="hljs-keyword">string</span> SignedBy</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Cancelled</span>(<span class="hljs-params">DateTime CancelledAt, <span class="hljs-keyword">string</span> Reason</span>)</span>;

<span class="hljs-comment">// Each state carries relevant data</span>
<span class="hljs-keyword">var</span> statusMessage = order.Status. Match(
    pending =&gt; <span class="hljs-string">$"Order placed on <span class="hljs-subst">{pending.OrderedAt:d}</span>"</span>,
    processing =&gt; <span class="hljs-string">$"Processing in warehouse <span class="hljs-subst">{processing.WarehouseId}</span>"</span>,
    shipped =&gt; <span class="hljs-string">$"Shipped via <span class="hljs-subst">{shipped.Carrier}</span>, tracking:  <span class="hljs-subst">{shipped.TrackingNumber}</span>"</span>,
    delivered =&gt; <span class="hljs-string">$"Delivered on <span class="hljs-subst">{delivered.DeliveredAt:d}</span>, signed by <span class="hljs-subst">{delivered.SignedBy}</span>"</span>,
    cancelled =&gt; <span class="hljs-string">$"Cancelled: <span class="hljs-subst">{cancelled.Reason}</span>"</span>
);
</code></pre>
<p>Why not just use an enum?</p>
<ul>
<li><p>Enums only store the state – they can't carry additional data</p>
</li>
<li><p>With OneOf, <code>Processing</code> knows which warehouse, and <code>Shipped</code> knows the tracking number offering more functionality and potential other logic to be carried out easily</p>
</li>
<li><p>Type-safe access to state-specific data</p>
</li>
<li><p>Impossible to access wrong data for a state (compiler prevents it)</p>
</li>
</ul>
<h3 id="heading-use-case-3-multi-channel-notifications">Use Case 3: Multi-Channel Notifications</h3>
<p>Sending notifications through different channels, each with different requirements:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">EmailNotification</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> To, <span class="hljs-keyword">string</span> Subject, <span class="hljs-keyword">string</span> Body</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">SmsNotification</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> PhoneNumber, <span class="hljs-keyword">string</span> Message</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">PushNotification</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> DeviceToken, <span class="hljs-keyword">string</span> Title, <span class="hljs-keyword">string</span> Body</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">InAppNotification</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> UserId, <span class="hljs-keyword">string</span> Message</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">SendNotification</span>(<span class="hljs-params">
    OneOf&lt;EmailNotification, SmsNotification, PushNotification, InAppNotification&gt; notification</span>)</span>
{
    <span class="hljs-keyword">await</span> notification.Match(
        <span class="hljs-keyword">async</span> email =&gt; <span class="hljs-keyword">await</span> _emailService.SendAsync(email.To, email.Subject, email.Body),
        <span class="hljs-keyword">async</span> sms =&gt; <span class="hljs-keyword">await</span> _smsService.SendAsync(sms.PhoneNumber, sms.Message),
        <span class="hljs-keyword">async</span> push =&gt; <span class="hljs-keyword">await</span> _pushService.SendAsync(push.DeviceToken, push.Title, push.Body),
        <span class="hljs-keyword">async</span> inApp =&gt; <span class="hljs-keyword">await</span> _notificationRepo.CreateAsync(inApp.UserId, inApp.Message)
    );
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">await</span> SendNotification(<span class="hljs-keyword">new</span> EmailNotification(<span class="hljs-string">"user@example.com"</span>, <span class="hljs-string">"Welcome"</span>, <span class="hljs-string">"Hello! "</span>));
<span class="hljs-keyword">await</span> SendNotification(<span class="hljs-keyword">new</span> SmsNotification(<span class="hljs-string">"+1234567890"</span>, <span class="hljs-string">"Your code is 123456"</span>));
</code></pre>
<p>Benefits:</p>
<ul>
<li><p>Could have a single, unified notification interface</p>
</li>
<li><p>Each channel has exactly the parameters it needs</p>
</li>
<li><p>No optional/nullable properties for irrelevant fields</p>
</li>
<li><p>Clear routing logic</p>
</li>
</ul>
<h3 id="heading-use-case-4-file-format-handling">Use Case 4: File Format Handling</h3>
<p>Handling different file types and data formats:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">CsvData</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] Lines</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">JsonData</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Content</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ExcelData</span>(<span class="hljs-params">IWorkbook Workbook</span>)</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> OneOf&lt;CsvData, JsonData, ExcelData&gt; <span class="hljs-title">LoadDataFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> path</span>)</span>
{
    <span class="hljs-keyword">var</span> extension = Path.GetExtension(path).ToLower();

    <span class="hljs-keyword">return</span> extension <span class="hljs-keyword">switch</span>
    {
        <span class="hljs-string">". csv"</span> =&gt; <span class="hljs-keyword">new</span> CsvData(File.ReadAllLines(path)),
        <span class="hljs-string">".json"</span> =&gt; <span class="hljs-keyword">new</span> JsonData(File.ReadAllText(path)),
        <span class="hljs-string">".xlsx"</span> =&gt; <span class="hljs-keyword">new</span> ExcelData(LoadExcelFile(path)),
        _ =&gt; <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedFileFormatException(extension)
    };
}

<span class="hljs-comment">// Process different formats uniformly</span>
<span class="hljs-keyword">var</span> data = LoadDataFile(filePath);
<span class="hljs-keyword">var</span> records = data.Match(
    csv =&gt; ParseCsv(csv.Lines),
    json =&gt; ParseJson(json.Content),
    excel =&gt; ParseExcel(excel.Workbook)
);
</code></pre>
<p>This is perfect for:</p>
<ul>
<li><p>APIs that offer multiple export formats</p>
</li>
<li><p>Import wizards that accept various file types</p>
</li>
<li><p>Configuration loaders supporting multiple formats</p>
</li>
</ul>
<h2 id="heading-key-benefits-of-oneof">Key Benefits of OneOf</h2>
<p>OneOf shines when you have:</p>
<ul>
<li><p>Multiple valid return types that don't share a common base class</p>
</li>
<li><p>Different data shapes for different scenarios</p>
</li>
<li><p>Type-safe branching where you want the compiler to enforce handling all cases</p>
</li>
<li><p>Domain modeling where different states carry different information</p>
</li>
<li><p>Explicit outcomes that should be part of the method signature</p>
</li>
</ul>
<p>It's essentially a way to say "this method returns <strong>A</strong> or <strong>B</strong> or <strong>C</strong>" in a type-safe way, forcing consumers to explicitly handle each possibility. This leads to more robust, self-documenting code that's harder to misuse.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>OneOf brings the power of discriminated unions to C#, enabling more expressive and type-safe code across numerous scenarios. Whether you're modeling payment methods, order states, notification channels, or error handling, OneOf provides a clean, compiler-enforced way to handle multiple return types.</p>
<p>Start incorporating OneOf into your projects, and you'll find your code becomes more intentional, easier to maintain, and less error-prone.</p>
<p>As always, if you’ve enjoyed reading this article feel free to <a target="_blank" href="https://x.com/grantdotdev">reach out on Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Serverless and Microservices with C# & Azure ]]>
                </title>
                <description>
                    <![CDATA[ You can learn modern application architecture by building real-world serverless and microservices solutions using C# and Azure. We just posted a full course on the freeCodeCamp YouTube channel that will teach you to build scaleable cloud applications... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/serverless-and-microservices-with-c-and-azure/</link>
                <guid isPermaLink="false">69023c73147abcc15caef5c4</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 29 Oct 2025 16:10:27 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761754162686/963ecd38-8522-4fee-8448-d4e1e5a3a9f0.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You can learn modern application architecture by building real-world serverless and microservices solutions using C# and Azure.</p>
<p>We just posted a full course on the freeCodeCamp YouTube channel that will teach you to build scaleable cloud applications. Muhammad Abdullah developed this course.</p>
<p>This hands-on course takes you from fundamental concepts to production-ready implementations, covering everything from Azure Functions and Docker containers to advanced orchestration with Kubernetes and .NET Aspire.</p>
<p>Here are the sections in this course:</p>
<ul>
<li><p>What is Serverless?</p>
</li>
<li><p>Understanding Serverless Architecture</p>
</li>
<li><p>Microservices Types &amp; Patterns Explained</p>
</li>
<li><p>Onion Architecture Explained</p>
</li>
<li><p>Docker Demystified</p>
</li>
<li><p>Azure Functions and Triggers</p>
</li>
<li><p>Background Functions in Azure</p>
</li>
<li><p>IoT Functions</p>
</li>
<li><p>Microservices in Practice - Route Planning</p>
</li>
<li><p>Introduction to Kubernetes</p>
</li>
</ul>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/xHUwGx-ZlTM">the freeCodeCamp.org YouTube channel</a> (5-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/xHUwGx-ZlTM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Loops in C# ]]>
                </title>
                <description>
                    <![CDATA[ Writing the same code repeatedly is poor practice in C# and doesn’t follow the Don’t Repeat Yourself (DRY) principle. But, there are many times in programming where you need to repeat commands, operations, or computations multiple times — perhaps cha... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-loops-in-c/</link>
                <guid isPermaLink="false">68caa6382769a3737407de1b</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Loops ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Wed, 17 Sep 2025 12:14:48 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757595108095/f7bd2673-3da5-4f34-8541-64cc8129fe96.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Writing the same code repeatedly is poor practice in C# and doesn’t follow the Don’t Repeat Yourself (DRY) principle. But, there are many times in programming where you need to repeat commands, operations, or computations multiple times — perhaps changing one small thing each iteration.</p>
<p>This is where loops come in. In this article, you’ll learn:</p>
<ul>
<li><p>How to create your first loop</p>
</li>
<li><p>Benefits and caveats of using loops</p>
</li>
<li><p>The different types of loops in C# and how to use them</p>
</li>
<li><p>When it’s best to use each one</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-use-a-for-loop-in-c">How to Use a For Loop in C</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-a-foreach-loop-in-c">How to Use a ForEach Loop in C</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-a-dowhile-loop-in-c">How to Use a Do..While Loop in C</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-a-while-loop-in-c">How to Use a While Loop in C</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts-choosing-the-right-loop">Final Thoughts: Choosing the Right Loop</a></p>
</li>
</ul>
<p>Let’s get started. Open your preferred IDE or coding editor and create a new Console Application in .Net 8+.</p>
<h2 id="heading-how-to-use-a-for-loop-in-c">How to Use a For Loop in C</h2>
<p>A for loop repeats a block of code a set number of times by:</p>
<ul>
<li><p>Initialising a loop variable.</p>
</li>
<li><p>Checking a condition before each iteration.</p>
</li>
<li><p>Updating the loop variable after each iteration.</p>
</li>
</ul>
<p>You can create a <code>for</code> loop with the code below:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// number of iterations</span>
<span class="hljs-keyword">var</span> totalIterations = <span class="hljs-number">5</span>

<span class="hljs-comment">// the loop</span>
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt;= totalIterations; i++){
   Console.Write(<span class="hljs-string">$"<span class="hljs-subst">{i}</span>,"</span>);
}

<span class="hljs-comment">// Output</span>
<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,
</code></pre>
<p><strong>Breaking it down:</strong></p>
<ul>
<li><p><code>for</code> — declares the loop</p>
</li>
<li><p><code>int i = 0;</code> — sets the starting point for the loop variable <code>i</code></p>
</li>
<li><p><code>i &lt;= totalIterations;</code> — the condition to keep looping. The code inside the loop runs only if this is true.</p>
</li>
<li><p><code>i++</code> — shorthand for “increase <code>i</code> by 1” after each iteration</p>
</li>
</ul>
<h3 id="heading-iterations-and-zero">Iterations and Zero</h3>
<p>Why does the example print six numbers when <code>totalIterations</code> is 5? C# uses zero-based indexing. Counting from 0 → 5 includes six numbers: 0,1,2,3,4,5.</p>
<p>If you want to print 1 → 5 instead, start <code>i</code> at 1:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> totalIterations = <span class="hljs-number">5</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i &lt;= totalIterations; i++)
{
    Console.Write(<span class="hljs-string">$"<span class="hljs-subst">{i}</span>,"</span>);
}
<span class="hljs-comment">// Output: 1,2,3,4,5</span>
</code></pre>
<p><strong>Tip:</strong><br>In general, <code>for</code> loops are used for indexing/accessing elements in collections, so it’s common practice to start your loop variable at 0 and use <code>&lt;</code> (less than) a given number or length of the collection.</p>
<h3 id="heading-reversal-of-direction">Reversal of Direction</h3>
<p>You can reverse a <code>for</code> loop by starting at the end and decrementing <code>i</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">5</span>; i &gt; <span class="hljs-number">0</span>; i--)
{
    Console.Write(<span class="hljs-string">$"<span class="hljs-subst">{i}</span>,"</span>);
}
<span class="hljs-comment">// Output: 5,4,3,2,1</span>
</code></pre>
<p>The loop checks if <code>i &gt; 0</code>. After each iteration, <code>i</code> decreases by 1, printing numbers in descending order.</p>
<h3 id="heading-other-uses-of-for-loops">Other Uses of For Loops</h3>
<p>Let’s say you want to access every other item in a list. This is where the power of <code>for</code> loops come in, and we can maximise our <code>loop variable</code>, using it as an index accessor.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Address</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">string</span>.Empty;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AddressLineOne { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">string</span>.Empty;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> HouseNumber { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> PostCode { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">string</span>.Empty;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Telephone { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">string</span>.Empty;
}

<span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> addressBook = <span class="hljs-keyword">new</span> List&lt;Address&gt;
        {
            <span class="hljs-keyword">new</span> Address
            {
                Name = <span class="hljs-string">"Grant"</span>, AddressLineOne = <span class="hljs-string">"Developer Avenue"</span>, HouseNumber = <span class="hljs-number">1</span>, PostCode = <span class="hljs-string">"DV19 8EP"</span>,
                Telephone = <span class="hljs-string">"0102919 93020-92019"</span>
            },
            <span class="hljs-keyword">new</span> Address
            {
                Name = <span class="hljs-string">"Bill"</span>, AddressLineOne = <span class="hljs-string">"Developer Avenue"</span>, HouseNumber = <span class="hljs-number">19</span>, PostCode = <span class="hljs-string">"DV19 8EP"</span>,
                Telephone = <span class="hljs-string">"0102919 93020-92019"</span>
            },
            <span class="hljs-keyword">new</span> Address
            {
                Name = <span class="hljs-string">"Rebecca"</span>, AddressLineOne = <span class="hljs-string">"Developer Avenue"</span>, HouseNumber = <span class="hljs-number">4</span>, PostCode = <span class="hljs-string">"DV19 8EP"</span>,
                Telephone = <span class="hljs-string">"0102919 93020-92019"</span>
            },
            <span class="hljs-keyword">new</span> Address
            {
                Name = <span class="hljs-string">"Amy"</span>, AddressLineOne = <span class="hljs-string">"Rower Avenue"</span>, HouseNumber = <span class="hljs-number">1</span>, PostCode = <span class="hljs-string">"DV19 8EP"</span>,
                Telephone = <span class="hljs-string">"0102919 93020-92019"</span>
            },
            <span class="hljs-keyword">new</span> Address
            {
                Name = <span class="hljs-string">"Joe"</span>, AddressLineOne = <span class="hljs-string">"Olympic Drive"</span>, HouseNumber = <span class="hljs-number">1</span>, PostCode = <span class="hljs-string">"DV19 10E"</span>,
                Telephone = <span class="hljs-string">"0102919 93020-92019"</span>
            }
        };

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; addressBook.Count; i += <span class="hljs-number">2</span>)
        {
            Console.WriteLine(<span class="hljs-string">$"Name: <span class="hljs-subst">{addressBook[i].Name}</span>, PostCode: <span class="hljs-subst">{addressBook[i].PostCode}</span>"</span>);
        }
    }
}

<span class="hljs-comment">/* Ouput:
Name: Grant, PostCode: DV19 8EP
Name: Rebecca, PostCode: DV19 8EP
Name: Joe, PostCode: DV19 10E
*/</span>
</code></pre>
<h3 id="heading-whats-happening"><strong>What’s Happening:</strong></h3>
<ul>
<li><p><code>i</code> starts at 0 and increases by 2 (<code>i += 2</code>) each iteration</p>
</li>
<li><p><code>addressBook[i]</code> now accesses every other item</p>
</li>
<li><p>This shows the power of using <code>i</code> as an index</p>
</li>
</ul>
<p>So far we’ve seen how <code>for</code> loops give control over indexes and step sizes.</p>
<p>But sometimes you just want to loop through every item in a collection, without worrying about indexes. That’s where the foreach loop shines.</p>
<h2 id="heading-how-to-use-a-foreach-loop-in-c">How to Use a ForEach Loop in C</h2>
<p>A <code>foreach</code> loop iterates over any object that inherits from <code>IEnumerable</code> (lists, arrays, collections). It automatically accesses each item in order, so you don’t need an index.</p>
<h3 id="heading-how-to-write-a-foreach-loop">How To Write a ForEach Loop</h3>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> characters = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;{<span class="hljs-string">"Batman"</span>, <span class="hljs-string">"CatWoman"</span>, <span class="hljs-string">"The Joker"</span>,<span class="hljs-string">"Harley Quinn"</span>};

<span class="hljs-keyword">foreach</span>(<span class="hljs-keyword">var</span> character <span class="hljs-keyword">in</span> characters){
    Console.WriteLine(character);
}

<span class="hljs-comment">/* Output:
Batman
CatWoman
The Joker
Harley Quinn
*/</span>
</code></pre>
<p><strong>Key points:</strong></p>
<ul>
<li><p>No need for indexes</p>
</li>
<li><p>Works with any enumerable collection</p>
</li>
<li><p>Cleaner, more expressive code</p>
</li>
</ul>
<h3 id="heading-caveats-of-foreach-loop">Caveats of ForEach Loop</h3>
<h4 id="heading-no-indexing">No Indexing</h4>
<p>You can’t directly access items with <code>addressBook[i]</code> inside a foreach. That’s because <code>foreach</code> works on <code>IEnumerable</code>, which doesn’t expose indexes.</p>
<h4 id="heading-performance">Performance</h4>
<p>A <code>foreach</code> loop has a small overhead compared to a <code>for</code> loop. In most cases this won’t matter, but in performance-critical code, a <code>for</code> loop may be faster.</p>
<h4 id="heading-modifying-items">Modifying Items</h4>
<p><code>foreach</code> gives you a copy of the current item, not a direct reference. That means you can’t reassign values to the list items inside the loop.</p>
<ul>
<li><p>You can read properties.</p>
</li>
<li><p>You can’t update the items themselves (use a for loop for that).</p>
</li>
</ul>
<p><code>foreach</code> is ideal when you want to visit every item, but not control the number of iterations.</p>
<h2 id="heading-how-to-use-a-dowhile-loop-in-c">How to Use a Do..While Loop in C</h2>
<p><code>do..while</code> loops run code at least once, then repeat while a condition is true:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">int</span> num;
<span class="hljs-keyword">do</span> {
    Console.Write(<span class="hljs-string">"Enter a positive number: "</span>);
    num = <span class="hljs-keyword">int</span>.Parse(Console.ReadLine());
} <span class="hljs-keyword">while</span> (num &lt;= <span class="hljs-number">0</span>);

Console.WriteLine(num);
</code></pre>
<p>The above code requests a number to be entered within the console application if the condition is met. That is, if a positive number is provided, the code will not ask for another, exiting the loop.</p>
<p>Should the user enter a negative number, it would continue to loop, requesting a positive number to be entered.</p>
<p>What if you didn’t want the code to run at least once, and only if a condition is met? This where you can use a <code>while</code> loop.</p>
<h2 id="heading-how-to-use-a-while-loop-in-c">How to Use a While Loop in C</h2>
<p><code>while</code> loops repeat code as long as a condition is true, but the body may never run if the condition is initially false:</p>
<p>We can use an example of a darts score board:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> sum = <span class="hljs-number">0</span>;
<span class="hljs-keyword">var</span> dartsThrown = <span class="hljs-number">0</span>;
<span class="hljs-keyword">var</span> random = <span class="hljs-keyword">new</span> Random();

<span class="hljs-keyword">while</span> (sum &lt; <span class="hljs-number">180</span> &amp;&amp; dartsThrown &lt; <span class="hljs-number">3</span>)
{
    <span class="hljs-keyword">var</span> dartScore = random.Next(<span class="hljs-number">61</span>); <span class="hljs-comment">// 0–60</span>
    sum += dartScore;
    dartsThrown++;
}

Console.WriteLine(<span class="hljs-string">"Your score is "</span> + sum);
</code></pre>
<p>While the player has darts to throw, the code will pick a number at random and increase their score.</p>
<p><strong>Tip:</strong> Always include code that changes the condition, or you risk creating an infinite loop. An infinite loop, is a loop which never stops, and causes your application to break.</p>
<p>You’ve seen four different ways to repeat code in C#: <code>for</code>, <code>foreach</code>, <code>do..while</code>, and <code>while</code>. Let’s summarise when to use each one.</p>
<h2 id="heading-final-thoughts-choosing-the-right-loop">Final Thoughts: Choosing the Right Loop</h2>
<p>C# gives us several types of loops. Choosing the right one makes your code readable, efficient, and intentional.</p>
<ul>
<li><p><strong>For Loop:</strong> Use when you know how many times to run something, or when you need an index, like using arrays, skipping items. Use a <code>for</code> loop when you need more control over the iterative nature of the loop.</p>
</li>
<li><p><strong>ForEach Loop:</strong> Use when you want to iterate through every item in a collection without worrying about indexes.</p>
</li>
<li><p><strong>While Loop:</strong> Use when you don’t know in advance how many times to run the code, but a condition drives the loop.</p>
</li>
<li><p><strong>Do..While Loop:</strong> Use when the loop body must run at least once, such as for user input or retry logic.</p>
</li>
</ul>
<p>By matching the loop type to your intent, your code will be correct, readable, and maintainable.</p>
<p>I hope this tutorial was useful, and as always I’d love to hear your thoughts and discuss further on social media. You can find me on <a target="_blank" href="https://x.com/grantdotdev">twitter/x</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript vs C#: How to Choose the Right Language as a Beginner ]]>
                </title>
                <description>
                    <![CDATA[ If you're just starting your coding journey or trying to pick your next language, two names you’ll often hear — among others — are JavaScript and C#. Both are powerful, widely used, and respected in the software world. But they serve different purpos... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/choose-the-right-language-js-vs-c-sharp/</link>
                <guid isPermaLink="false">6893b598ffc433dd809aa59d</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Wed, 06 Aug 2025 20:05:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754510673710/75f0501b-9d42-43ee-bc90-cc028afdeb3a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're just starting your coding journey or trying to pick your next language, two names you’ll often hear — among others — are JavaScript and C#. Both are powerful, widely used, and respected in the software world.</p>
<p>But they serve different purposes, feel different to write, and open up different types of job opportunities.</p>
<p>This article will help you understand what each language is, what they’re good at, and how they compare in real-world use cases.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-javascript">What Is JavaScript?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-c">What Is C#?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance">Performance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-community-and-support">Community and Support</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ease-of-learning">Ease of Learning</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-career-opportunities">Career Opportunities</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ul>
<h2 id="heading-what-is-javascript">What Is JavaScript?</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/what-is-javascript-definition-of-js/">JavaScript</a> is the language of the web. It runs in your browser and powers everything from simple websites to complex web apps. Want to make a button do something when clicked? That’s JavaScript. Want to load data without reloading the page? JavaScript again.</p>
<p>But here’s the cool part, JavaScript isn’t just for the front end anymore. With <a target="_blank" href="https://nodejs.org/en">Node.js</a>, it can run on servers too. This means JavaScript is now used to build entire applications, front to back. You can build APIs, handle databases, run background jobs, and more, all with the same language.</p>
<p>This makes JavaScript beginner-friendly. You can write your first script in a browser and still use the same language to build large systems. It’s fast to start, and you’ll find lots of resources and jobs if you go down this path.</p>
<h2 id="heading-what-is-c"><strong>What Is C#?</strong></h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/learn-c-sharp-programming-1/">C# (pronounced “C sharp”)</a> is a language built by Microsoft. It’s often used in combination with the .NET framework to create desktop apps, web services, and enterprise software. If a business runs a Windows-based software, chances are that it’s built with C#.</p>
<p>C# is also a top choice for game development, thanks to its strong connection with <a target="_blank" href="https://unity.com/">Unity</a>, one of the most popular game engines in the world.</p>
<p>Unlike JavaScript, C# is statically typed. This means you need to define your variables clearly and follow more rules. That sounds like a lot at first, but it actually helps you catch errors early and keep big projects neat and tidy.</p>
<p>Now that you know what JavaScript and C# are, let’s compare them across five key areas.</p>
<h2 id="heading-performance"><strong>Performance</strong></h2>
<p>C# usually performs better than JavaScript, especially when dealing with heavy workloads or tasks that demand a lot from the processor. This advantage comes from the fact that C# is a compiled language.</p>
<p>When you run a C# program, the code is first converted into an intermediate language and then compiled into machine code that your computer’s processor can execute directly. This compilation step removes much of the overhead that comes with interpreting code on the fly.</p>
<p>The result is faster execution and more efficient memory usage, which makes C# ideal for scenarios like handling large files, running complex mathematical calculations, or powering game engines where every millisecond counts.</p>
<p>JavaScript works differently. It’s an interpreted language, which means the code runs line by line in a runtime environment like a web browser or Node.js. Instead of being compiled to machine code ahead of time, the JavaScript engine reads and executes the code as it runs.</p>
<p>This approach offers flexibility and makes it easy to develop and deploy scripts quickly, which is a big reason why JavaScript dominates web development. But because it doesn’t have the same direct link to the machine as compiled languages do, it can struggle in situations that require extremely high performance, like processing massive datasets, rendering complex graphics, or building high-frequency trading systems.</p>
<p>However, modern JavaScript engines have come a long way. Engines like V8, which powers Chrome and Node.js, use <a target="_blank" href="https://en.wikipedia.org/wiki/Just-in-time_compilation">Just-In-Time (JIT)</a> compilation to optimize code while it’s running. They can identify patterns and compile parts of the code into machine instructions on the fly, dramatically improving speed compared to older interpreters.</p>
<p>This means that for most everyday web applications, the difference in performance between JavaScript and C# won’t be noticeable. Web dashboards, e-commerce sites, and typical server-side APIs run perfectly fine in JavaScript. But if your project involves raw computational power, game graphics, or real-time simulations, C# will still give you a clear edge.</p>
<h2 id="heading-community-and-support"><strong>Community and Support</strong></h2>
<p>JavaScript has one of the largest and most active developer communities in the world. Since it's used in almost every corner of the tech world, from websites and browsers to mobile apps and even desktop apps, it has become a go-to language for millions of developers.</p>
<p>That popularity means you’re never alone when learning or building with JavaScript. Whatever problem you run into, chances are that someone else has already faced it and posted about it online. Whether you prefer watching YouTube tutorials, reading blog posts, browsing GitHub repositories, or asking questions on Stack Overflow, you’ll find an overwhelming amount of help and resources to guide you.</p>
<p>C# also has a strong and dedicated community, though it’s more concentrated in the enterprise and professional development space. Backed by Microsoft, C# is consistently updated, well-documented, and deeply integrated with tools like Visual Studio and the .NET ecosystem.</p>
<p>You’ll find a wealth of high-quality documentation, official guides, and forums where professionals share their knowledge. While it might not generate the same buzz as JavaScript in startup circles or web-first communities, C# has a long-standing presence in large-scale systems, corporate software, game development (especially with Unity), and Windows applications. In those environments, it’s not uncommon to find teams of seasoned developers with years of experience in C#.</p>
<p>In short, both languages enjoy excellent support. JavaScript might feel more beginner-friendly due to its widespread usage and endless online tutorials, making it easy to pick up quickly. C#, on the other hand, shines in more structured, professional settings where stability, performance, and long-term maintainability are key. It may not have the same trendy reputation, but within its ecosystem, it’s trusted, respected, and well-loved.</p>
<h2 id="heading-ease-of-learning"><strong>Ease of Learning</strong></h2>
<p>JavaScript is one of the easiest languages to start with because it requires almost no setup. You can open your browser, type a few lines of code in the console, and immediately see the results.</p>
<p>This instant feedback loop makes learning feel exciting and interactive, especially for beginners who want to experiment and see quick outcomes. You can start small, tweak your code, and watch it come to life without installing tools, setting up projects, or even leaving the browser. This low barrier to entry is one of the biggest reasons JavaScript has become the go-to language for people taking their very first steps in programming.</p>
<p>But this simplicity comes with quirks. JavaScript is a very flexible language, which is both a blessing and a curse. It often lets you write code that “just works,” even if it isn’t the best approach. While this makes it forgiving in the early stages, it can also lead to confusing bugs down the line.</p>
<p>Small mistakes might not throw errors immediately, and behavior can change in unexpected ways. Anyone who has wrestled with tricky type conversions knows that JavaScript’s freedom can sometimes backfire. This flexibility demands that you develop discipline on your own if you want to avoid messy, hard-to-maintain code.</p>
<p>C#, on the other hand, feels more structured from the start. It enforces rules like defining types, organizing code into classes, and following a clear syntax. This can feel strict and even a little intimidating at first because you can’t just write anything and hope it works.</p>
<p>The compiler checks your code before it runs and points out mistakes early, which can be frustrating as a beginner. But this structure pays off as your projects grow. The rules and strong typing help you catch errors before they become serious problems, guide you toward better programming habits, and make large, complex codebases easier to manage. Once you get used to its style, C# actually makes programming feel more predictable and less error-prone.</p>
<p>In simple terms, JavaScript gives you the quickest path to start coding and see results, which is perfect for learning and experimenting. C# takes longer to warm up to, but it rewards that effort with cleaner, safer, and more maintainable projects as they grow in size and complexity.</p>
<h2 id="heading-career-opportunities"><strong>Career Opportunities</strong></h2>
<p>Learning JavaScript unlocks a wide range of career opportunities because it powers so much of the modern digital world.</p>
<p>Starting with front-end development, you can build interactive websites and web applications that run in the browser using frameworks like <a target="_blank" href="https://react.dev/">React</a>, Vue, or Angular. If you want to go deeper, Node.js allows you to use JavaScript for back-end development as well, which means you can handle server logic, databases, and APIs without ever switching languages.</p>
<p>This flexibility makes full-stack roles especially accessible to JavaScript developers, since you can manage both the front-end and back-end with a single skillset. On top of that, JavaScript extends into mobile app development with tools like React Native and Ionic, letting you build apps for both iOS and Android.</p>
<p>Because nearly every business needs a website or web application, the demand for JavaScript developers is both high and consistent, making it a strong career path for anyone entering the tech industry.</p>
<p>C# leads to a slightly different set of roles, often tied to enterprise or specialized development. It is heavily used in backend systems that run on the .NET ecosystem, where reliability and performance are critical. Many large companies rely on C# for internal tools, financial applications, and large-scale software products that power their core operations.</p>
<p>One of the most exciting areas for C# developers is game development, thanks to its deep integration with Unity, the most popular game engine in the world. From indie studios to major game companies, Unity uses C# as its primary scripting language, opening the door to careers in the gaming industry. Additionally, C# is a natural fit for building Windows desktop applications and enterprise-level cloud solutions, especially within companies already invested in Microsoft technologies.</p>
<p>Both languages can lead to solid salaries and stable careers, but the paths they open are different. JavaScript thrives in web and mobile-focused roles with a steady demand across startups, agencies, and tech companies of all sizes. C# excels in enterprise, backend, and game development, where the projects are often larger, more complex, and built for long-term reliability. Choosing between them really comes down to the type of work that excites you most and the industry you want to grow in.</p>
<h2 id="heading-final-thoughts"><strong>Final Thoughts</strong></h2>
<p>JavaScript and C# are both modern, useful, and in demand. JavaScript is light, fast, and flexible, perfect for websites and small-to-large web apps. C# is powerful, structured, and ideal for Windows apps, enterprise systems, and games.</p>
<p>If you're new to coding and want to see results fast, start with JavaScript. If you're interested in game dev or building strong business apps, try C#.</p>
<p>You don’t have to choose forever. Many developers learn both. Start with one, explore the other later, and you’ll become a well-rounded coder ready for anything.</p>
<p><a target="_blank" href="https://blog.manishshivanandhan.com/">Join my newsletter</a> for a summary of my articles every Friday. You can also <a target="_blank" href="https://linkedin.com/in/manishmshiva">connect with me on Linkedin</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Assign Dataverse Security Roles at Scale ]]>
                </title>
                <description>
                    <![CDATA[ Assigning Dataverse security roles manually works pretty well – until it doesn't. Whether you are onboarding 50 new hires or rolling out access to a new app, managing roles by hand can be tedious and  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-assign-dataverse-security-roles-at-scale/</link>
                <guid isPermaLink="false">68557b4d4b011b57124c6b6b</guid>
                
                    <category>
                        <![CDATA[ Power Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dataverse ]]>
                    </category>
                
                    <category>
                        <![CDATA[ power-automate ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brandon Wozniewicz ]]>
                </dc:creator>
                <pubDate>Fri, 20 Jun 2025 15:16:29 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750432574148/b3cfaebe-7566-4795-b00e-5da9d65dd8f4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Assigning Dataverse security roles manually works pretty well – until it doesn't.</p>
<p>Whether you are onboarding 50 new hires or rolling out access to a new app, managing roles by hand can be tedious and error-prone.</p>
<p>In this article, you will learn about three scalable ways to assign security roles across multiple users or teams, with low-code and pro-code options.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ol>
<li><p><a href="#heading-aside-teams">Aside: Teams</a></p>
</li>
<li><p><a href="#heading-canvas-apps-relate-unrelate-functions">Canvas Apps Relate / Unrelate Functions</a></p>
</li>
<li><p><a href="#heading-power-automate-with-the-relate-rows-in-dataverse-action">Power Automate with the Relate Rows in Dataverse Action</a></p>
</li>
<li><p><a href="#heading-c-console-app-using-the-dataverse-sdk">C# Console App: Using the Dataverse SDK</a></p>
</li>
<li><p><a href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ol>
<h2 id="heading-aside-teams">Aside: Teams</h2>
<p>Teams are the simplest way to assign roles to multiple users.</p>
<p>Dataverse admins and team owners can add users to one or more teams. Rather than assigning roles to individual users, the security role is assigned to the team.</p>
<p>But there are caveats: record ownership and team management can introduce their own complexity. In environments with many teams, updating security roles can become just as tedious as assigning them individually.</p>
<p>This article focuses on <strong>programmatic individual assignments</strong>, but keep in mind that all three methods described below can be adapted to work with teams as well.</p>
<h2 id="heading-canvas-apps-relate-unrelate-functions">Canvas Apps Relate / Unrelate Functions</h2>
<p>Canvas app developers can use Power FX to assign security roles across users or teams. Minimal code is required, and the result can serve as a lightweight security role management portal.</p>
<p>While not ideal for massive batches, this approach is suitable for assigning roles to a few hundred users.</p>
<pre><code class="language-plaintext">ForAll(
    colSelectedUsers As User,
    Relate(
        User.'Security Roles (systemuserroles_association)',
        cbx_securityRoles.Selected
    )
)
</code></pre>
<p>Here:</p>
<ul>
<li><p><code>colSelectedUsers</code> is a collection of users.</p>
</li>
<li><p><code>cbx_securityRoles</code> is a Combobox control holding the security role to assign.</p>
</li>
</ul>
<p>The <code>Relate</code> function connects each user with the selected security role. The first parameter is the many-to-many relationship (<code>systemuserroles_association</code>) between <code>systemuser</code> and <code>role</code>.</p>
<p>To find relationship names, open the User table &gt; <strong>Relationships</strong>. Then, look for many-to-many connections to the role table.</p>
<img src="https://scripted-bytes.ghost.io/content/images/2025/05/Snag_1e2ee592.png" alt="Image of user table relationships highlighting the system user roles association relationship" width="600" height="400" loading="lazy">

<p>The security role/user relationship is a many-to-many relationship.</p>
<h2 id="heading-power-automate-with-the-relate-rows-in-dataverse-action">Power Automate with the Relate Rows in Dataverse Action</h2>
<p>The <strong>Relate Rows in Dataverse</strong> action allows you to assign roles dynamically in cloud flows.</p>
<img src="https://scripted-bytes.ghost.io/content/images/2025/05/power-automate.jpg" alt="Image of cloud flow assigning security roles" width="600" height="400" loading="lazy">

<h3 id="heading-how-it-works">How it works:</h3>
<ul>
<li><p>Trigger a flow (for example, manually or via Dataverse trigger).</p>
</li>
<li><p>Fetch a list of users based on a condition.</p>
</li>
<li><p>Loop through each user with <strong>Apply to Each</strong>.</p>
</li>
<li><p>Assign a static or dynamic security role.</p>
</li>
</ul>
<h2 id="heading-c-console-app-using-the-dataverse-sdk">C# Console App: Using the Dataverse SDK</h2>
<p>This method offers maximum control and supports complex, high-scale role assignments – but it requires pro-code skills.</p>
<p><strong>Example:</strong></p>
<p>This console app:</p>
<ol>
<li><p>Connects to the environment via client credentials.</p>
</li>
<li><p>Retrieves all users with the title "Salesperson"</p>
</li>
<li><p>Builds a batch of associate requests.</p>
</li>
<li><p>Executes the batch transactionally – if one fails, all fail.</p>
</li>
</ol>
<pre><code class="language-csharp">using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;

class Program
{
    static void Main(string[] args)
    {
        string dataverseUrl = "https://your-org.crm.dynamics.com";
        string clientId     = "client-id-here";
        string clientSecret = "client-secret-here";
        string tenantId     = "tenant-id-here";

        string connectionString = $@"
            AuthType=ClientSecret;
            Url={dataverseUrl};
            ClientId={clientId};
            ClientSecret={clientSecret};
            TenantId={tenantId};
        ";
        // Connect to our environment
        using var serviceClient = new ServiceClient(connectionString);

        if (!serviceClient.IsReady)
        {
            Console.WriteLine("Failed to connect.");
            return;
        }

        // Fetch a list of users that we intend to associate a role with
        var query = new QueryExpression("systemuser")
        {
            ColumnSet = new ColumnSet("systemuserid"),
            Criteria = new FilterExpression
            {
                Conditions =
                {
                     new ConditionExpression(
                        "title",
                        ConditionOperator.Equal,
                        "Salesperson"
                     ),
                }
            }
        };

        var users = serviceClient.RetrieveMultiple(query);

        // Role to assign (pretend guid for demo purposes)
        var securityRoleId = new Guid(
            "00000000-0000-0000-0000-000000000ABC"
        );

        // Prepare our transaction
        var transaction = new ExecuteTransactionRequest
        {
            ReturnResponses = true,
            Requests = new OrganizationRequestCollection()
        };

        // For each user we fetched above, we add an associate request 
        // to the transaction
        foreach (var user in users.Entities)
        {
            var userId = (Guid)user["systemuserid"];

            var relationship = new Relationship(
                "systemuserroles_association"
            );

            var relatedReferences = new EntityReferenceCollection
            {
                new EntityReference(
                    "role",
                    securityRoleId
                )
            };
            // build the associate request
            var request = new AssociateRequest
            {
                Target = new EntityReference(
                    "systemuser",
                    userId
                ),
                RelatedEntities = relatedReferences,
                Relationship = relationship
            };
            // add the request to the transaction
            transaction.Requests.Add(request);
        }

        // Finally, execute the batch as a transaction
        serviceClient.Execute(transaction);
    }
}
</code></pre>
<p>You can even utilize this logic within a Custom API, allowing Power Automate or Canvas Apps to call it, blending low-code and pro-code capabilities.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>If your teams are already well-structured and manageable in number, <strong>teams remain the easiest way</strong> to assign roles at scale.</p>
<p>But when teams aren't feasible –&nbsp;or when assigning directly to users is required – each method we discussed here offers a viable alternative:</p>
<ul>
<li><p>Use <strong>Canvas Apps</strong> for lightweight, user-facing management portals</p>
</li>
<li><p>Use <strong>Power Automate</strong> when complexity is low and there is a need to trigger it in a variety of ways.</p>
</li>
<li><p>Use <strong>C# and the Dataverse SDK</strong> for full control and batch efficiency.</p>
</li>
</ul>
<p>Ready to automate your role assignments? Start small –&nbsp;build a simple Power App or Flow – and scale your approach from there.</p>
<p>Found this helpful? I write about practical automation, productivity systems, and building smarter workflows — without the jargon. Visit me at <a href="http://brandonwoz.com">brandonwoz.com</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use TestContainers in .Net ]]>
                </title>
                <description>
                    <![CDATA[ At some point in your development lifecycle, you will need to test that your system can integrate with another system, whether it be another API, a database, or caching service, for example. This can be a laborious task of spinning up other servers h... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-testcontainers-in-net/</link>
                <guid isPermaLink="false">67e2cbfdaa97659cd53cf39f</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testcontainers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Integration Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Tue, 25 Mar 2025 15:30:05 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742773343798/44c64acc-3862-4325-af21-6b7de417d300.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>At some point in your development lifecycle, you will need to test that your system can integrate with another system, whether it be another API, a database, or caching service, for example. This can be a laborious task of spinning up other servers hosting the 3rd party API replica, or permanently hosting a SQL database seeded with test data.</p>
<p>In this article, I’ll teach you how to use the TestContainers library to make running integration tests much easier and more manageable.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-testcontainers">What Is TestContainers?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-it-all-work">How Does It All Work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-first-test">How to Set Up Your First Test</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-behaviors-of-iasynclifetime-in-a-test-class">Key Behaviors of IAsyncLifetime in a Test Class</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-improve-performance">How to Improve Performance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-explanation-of-differences">Explanation of Differences</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-share-your-container-across-multiple-test-classes">How to Share Your Container Across Multiple Test Classes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary-of-approaches">Summary of Approaches:</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-multiple-containers">How to Create Multiple Containers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-make-your-setup-easier-with-custom-images">How to Make Your Setup Easier With Custom Images</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p>Understanding of Docker</p>
</li>
<li><p>Understanding of xUnit and testing</p>
</li>
<li><p>Installation of the following packages:</p>
<ul>
<li><p><code>TestContainers</code></p>
</li>
<li><p><code>TestContainers.MsSql</code></p>
</li>
<li><p>xUnit</p>
</li>
<li><p>&gt;= .Net 8</p>
</li>
<li><p><code>FluentAssertions</code></p>
</li>
<li><p><code>Microsoft.Data.SqlClient</code></p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-what-is-testcontainers">What Is TestContainers?</h2>
<p><a target="_blank" href="https://testcontainers.com">TestContainers</a> is an open source library that provides you with easily disposable container instances for things like database hosting, message brokers, browsers and more – basically anything that can run in a Docker container.</p>
<p>It removes the necessity to maintain hosted environments for testing in the cloud or on local machines. As long as the user’s machine and CI/CD host supports Docker, the testContainer tests can easily be run.</p>
<h2 id="heading-how-does-it-all-work">How Does It All Work?</h2>
<p>You define the image you’re wanting to utilise, and specify a configuration.</p>
<p>The TestContainer library spins up a Docker Container with the configured image.</p>
<h3 id="heading-provides-connection-details"><strong>Provides Connection Details</strong></h3>
<p>After starting the container, TestContainers exposes connection strings (for example, a database connection URL), so your tests can use the real service, rather than having to configure this yourself.</p>
<h3 id="heading-cleans-up-automatically"><strong>Cleans Up Automatically</strong></h3>
<p>When the test finishes, TestContainers removes the container automatically, ensuring no leftover resources. This is one of the best things about using TestContainers: all the creation, tear down, and container setup is handled within the library itself, making it perfect for use within delivery pipelines.</p>
<h2 id="heading-how-to-set-up-your-first-test">How to Set Up Your First Test</h2>
<p>For the purpose of this tutorial, we’re going to keep things simple, and only use a <code>MS Sql Server</code> image.</p>
<p>The first thing we’re going to do is configure our Microsoft SQL Server Docker container via the TestContainer fluid API.</p>
<p>Create your test class like below:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">IntegrationTests</span>: <span class="hljs-title">IAsyncLifetime</span> 
{
    <span class="hljs-keyword">private</span> MsSqlContainer _container;
    <span class="hljs-keyword">private</span> FakeLogger _<span class="hljs-function">logger

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InitializeAsync</span>(<span class="hljs-params"></span>)</span>
    {
           _container = <span class="hljs-keyword">new</span> MsSqlBuilder()
                .WithImage(<span class="hljs-string">"mcr.microsoft.com/mssql/server:2022-latest"</span>)
                .WithPassword(<span class="hljs-string">"P@ssw0rd123"</span>)
                .WithPortBinding(<span class="hljs-number">1443</span>)
                .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">1433</span>))
                .Build();

            _logger = <span class="hljs-keyword">new</span> FakeLogger();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span> =&gt; <span class="hljs-keyword">await</span> _container.DisposeAsync();
}
</code></pre>
<p>Here we’re using xUnit’s <code>IAsyncLifetime</code> interface. It’s an interface in xUnit that provides a way to handle async setup and teardown for test classes. It's useful when you need to initialise and clean up resources asynchronously. We’re using the <code>InitializeAsync()</code> to setup and define our Microsoft SQL Database container as well as starting the container, then using the <code>DisposeAsync()</code> method to stop and dispose of our container.</p>
<h3 id="heading-explanation-of-builder-methods">Explanation of Builder Methods</h3>
<ul>
<li><p><code>WithImage()</code>: this allows us to specify the image we want Docker to pull down and run. We’ve opted for the latest version of SQL Server 2022.</p>
</li>
<li><p><code>WithPassword()</code>: This allows us to specify the password for the database (when creating most databases, a password is normally required).</p>
</li>
<li><p><code>WithPortBinding()</code>: This allows us to specify both the hosting port number on your machine, as well as the container port number</p>
</li>
<li><p><code>WithWaitStrategy()</code>: Here we can specify a wait strategy, which informs our container to wait for a condition before the container is ready to use. This is important because some services (like databases or APIs) take time to fully start up.</p>
</li>
<li><p><code>Build()</code>" This is the command that builds the test container based on the configuration. This <strong>does not</strong> run or start the container – you can do this using the <code>container.StartAsync()</code> method as mentioned previously.</p>
</li>
</ul>
<h4 id="heading-why-is-withwaitstrategy-needed"><strong>Why Is</strong> <code>WithWaitStrategy()</code> Needed?</h4>
<p>By default, TestContainers assumes the container is ready as soon as it starts running. But some services might:</p>
<ul>
<li><p>Take time to initialize.</p>
</li>
<li><p>Require a specific log message before they are ready.</p>
</li>
<li><p>Need a port to be accessible before you can connect.</p>
</li>
</ul>
<p>Using <code>WithWaitStrategy()</code>, you can customise how TestContainers waits before considering the container "ready."</p>
<h3 id="heading-adding-the-test">Adding the Test</h3>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">IntegrationTests</span>: <span class="hljs-title">IAsyncLifetime</span> 
{
    <span class="hljs-keyword">private</span> MsSqlContainer _container;
    <span class="hljs-keyword">private</span> FakeLoger _logger;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InitializeAsync</span>(<span class="hljs-params"></span>)</span>
    {
           _container = <span class="hljs-keyword">new</span> MsSqlBuilder()
                .WithImage(<span class="hljs-string">"mcr.microsoft.com/mssql/server:2022-latest"</span>)
                .WithPassword(<span class="hljs-string">"P@ssw0rd123"</span>)
                .WithPortBinding(<span class="hljs-number">1443</span>)
                .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">1433</span>))
                .Build();

            <span class="hljs-keyword">await</span> _container.StartAsync();
            _logger = <span class="hljs-keyword">new</span> FakeLogger();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span> =&gt; <span class="hljs-keyword">await</span> _container.DisposeAsync();

    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Test_Database_Connection</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> connectionString = _container.GetConnectionString();
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> conn = <span class="hljs-keyword">new</span> SqlConnection(connectionString);
        <span class="hljs-keyword">await</span> conn.OpenAsync();

        Assert.True(conn.State == System.Data.ConnectionState.Open);
    }
}
</code></pre>
<p>The above test, although it’s simple, illustrates how easy it is to spin up a container and create a simple test. The above test will work, but it can lead to low performing tests and high usage of machine resource when not used correctly. Let me explain:</p>
<p>Using <code>IAsyncLifetime</code> is necessary, as we’re calling async setup methods (<code>StartAsync</code>), for example. But the <code>InitializeAsync() / DisposeAsync()</code> methods when situated in a test class are run before and after every test (<code>Fact</code> in xUnit).</p>
<p>This means that every time a test begins, it is:</p>
<ul>
<li><p>creating a brand new Docker container,</p>
</li>
<li><p>pulling the MS Sql image,</p>
</li>
<li><p>creating the DB,</p>
</li>
<li><p>running the tests, and</p>
</li>
<li><p>tearing down the container.</p>
</li>
</ul>
<p>You can test this by copying and pasting the above <code>Test_Database_Connection()</code> test multiple times, adding a number to each duplicate test (to keep the compiler happy), and opening Docker Desktop. Running all the tests, you will see a new container (with a different name) being created for each test run.</p>
<p>Now, this can be acceptable if you have a limited number of tests in your test class. But it can have negative outcomes on test classes with a larger number of tests, meaning test maintenance and planning is key. It’s useful, though, when you want to make sure that the database is in a completely clean state before each test, ensuring no data contamination from other tests running.</p>
<h2 id="heading-key-behaviors-of-iasynclifetime-in-a-test-class"><strong>Key Behaviors of</strong> <code>IAsyncLifetime</code> in a Test Class</h2>
<p>When your test class implements <code>IAsyncLifetime</code>, xUnit's default behaviour is:</p>
<p>1. Creates a new instance of the test class for each test method.<br>2. Calls <code>InitializeAsync()</code> before each test.<br>3. Calls <code>DisposeAsync()</code> after each test.</p>
<h3 id="heading-what-does-this-mean-for-testcontainers"><strong>What Does This Mean for TestContainers?</strong></h3>
<ul>
<li><p>In our case, since <code>InitializeAsync()</code> sets up a new container, a new container is created for each test.</p>
</li>
<li><p><code>DisposeAsync()</code> stops the container after each test finishes.</p>
</li>
<li><p>Ensures a completely fresh database state for every test, avoiding data contamination.</p>
</li>
<li><p>Is slow and resource-intensive, especially if you have many test methods.</p>
</li>
</ul>
<p>A more visual look on a test class could look like this:</p>
<p>🟢 InitializeAsync() -&gt; New Container Created (For Test_1)</p>
<p>🧪 Running Test_1</p>
<p><strong>🛑</strong> DisposeAsync() -&gt; Container Stopped (After Test_1)</p>
<p>🟢 InitializeAsync() -&gt; New Container Created (For Test_2)</p>
<p>🧪 Running Test_2</p>
<p><strong>🛑</strong> DisposeAsync() -&gt; Container Stopped (After Test_2)</p>
<h3 id="heading-when-is-this-useful"><strong>When Is This Useful?</strong></h3>
<ul>
<li><p>You need a completely fresh database state or container for each test.</p>
</li>
<li><p>Avoids test data contamination.</p>
</li>
<li><p>Each test starts from a clean slate.</p>
</li>
</ul>
<h3 id="heading-when-is-this-a-problem"><strong>When Is This a Problem?</strong></h3>
<ul>
<li><p>It results in slow execution – a new container is started for every test.</p>
</li>
<li><p>It’s resource-heavy – multiple containers run sequentially.</p>
</li>
<li><p>And it’s not scalable – hundreds of tests will take a long time to complete.</p>
</li>
</ul>
<h2 id="heading-how-to-improve-performance">How to Improve Performance</h2>
<p>Ok, so we’ve seen how to create containers once per test, and explored scenarios where this would be useful, but what if performance and cost are a concern?</p>
<p>Here we can combine <code>IClassFixture</code> and <code>IAsyncLiftetime</code> to achieve a <em>Once per test class</em> approach, where we create one container and one database, and its lifecycle is the full length of the test class (that is, all tests run against the same DB).</p>
<h3 id="heading-how-to-write-this">How to Write This</h3>
<p>We can utilise a TestFixture class which inherits the IAsyncLifetime interface, exposing the <code>InitializeAsync()</code> and <code>DisposeAsync()</code> methods as before.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> DotNet.Testcontainers.Builders;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Logging.Testing;
<span class="hljs-keyword">using</span> Testcontainers.MsSql;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">IntegrationTests</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TestClassFixture</span> : <span class="hljs-title">IAsyncLifetime</span>
{
    <span class="hljs-keyword">public</span> MsSqlContainer Container { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">private</span> FakeLogger _logger;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InitializeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        Container = <span class="hljs-keyword">new</span> MsSqlBuilder()
            .WithImage(<span class="hljs-string">"mcr.microsoft.com/mssql/server:2022-latest"</span>)
            .WithPassword(<span class="hljs-string">"P@ssw0rd123"</span>)
            .WithPortBinding(<span class="hljs-number">1443</span>)
            .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">1433</span>))
            .Build();

        _logger = <span class="hljs-keyword">new</span> FakeLogger();
        <span class="hljs-keyword">await</span> Container.StartAsync();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> Container.DisposeAsync();
    }
}
</code></pre>
<p>Using xUnit’s <code>IClassFixture</code> interface, we can pass our <code>TestClassFixture</code> and have our test class inherit from this. A test fixture is only run once per test class, making it perfect for our scenario.</p>
<pre><code class="lang-csharp">
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">IntegrationFixtureTests</span> : <span class="hljs-title">IClassFixture</span>&lt;<span class="hljs-title">TestClassFixture</span>&gt;
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _connectionString;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">IntegrationFixtureTests</span>(<span class="hljs-params">TestClassFixture testClassFixture</span>)</span>
    {
        _connectionString = testClassFixture.Container.GetConnectionString();

        <span class="hljs-comment">// other test class specific setup goes here</span>
    }

    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Test_Database_Connection</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> conn = <span class="hljs-keyword">new</span> SqlConnection(_connectionString);
        <span class="hljs-keyword">await</span> conn.OpenAsync();

        Assert.True(conn.State == System.Data.ConnectionState.Open);
    }
}
</code></pre>
<p>We now have a much cleaner test class, and all our container logic is handled by the <code>IClassFixture</code> instead. Should you need to add test class specific code, for example seeding the database prior to running, or the mocking of any resources, you can place this code within the constructor.</p>
<h2 id="heading-explanation-of-differences">Explanation of Differences</h2>
<p>We set our <code>Container</code> property as public, rather than private so that our test class can access the container. The test fixture is injected by xUnit's own internal dependency injection mechanics when you use <code>IClassFixture&lt;T&gt;</code>.</p>
<p>xUnit automatically creates an instance of the fixture class and passes it into the test class constructor.</p>
<p>The container is started within the <code>InitializeAsync()</code> method on the <strong>TestFixture</strong> now, rather than the test class, meaning it only gets started once and is readily available for all the tests. This improves performance and test speeds (no more waiting for each container to spin up before each test).</p>
<p>The test flow would look something more like this now:</p>
<p>🟢 InitializeAsync() → Container Created → Container Started</p>
<p>🧪 Running Test_1</p>
<p>🧪 Running Test_2</p>
<p><strong>🛑</strong> DisposeAsync() -&gt; Container Stopped → Container Disposed of</p>
<h3 id="heading-advantages-and-disadvantages">Advantages and Disadvantages</h3>
<h4 id="heading-faster-execution">✅ <strong>Faster Execution</strong></h4>
<p>Significantly reduces setup/teardown overhead, especially when using slow-starting services like databases.</p>
<h4 id="heading-lower-resource-usage">✅ <strong>Lower Resource Usage</strong></h4>
<p>Running a container once per test class consumes far fewer system resources compared to one container per test. This is especially beneficial when running integration tests in CI/CD pipelines where resource usage needs to be optimised to keep costs low.</p>
<h4 id="heading-more-realistic-testing">✅ <strong>More Realistic Testing</strong></h4>
<p>In real-world scenarios, applications don’t restart their databases between API calls, so why should your integration tests?</p>
<h4 id="heading-data-contamination">❌ <strong>Data Contamination</strong></h4>
<p>Effective test data management is essential for maintaining reliable tests. If test data is not properly isolated, it can lead to unintended interference between tests.</p>
<p>For example, a test that creates a new record might introduce unexpected data, causing a retrieval test to fail if it runs afterward. This type of data contamination is a common issue when all tests in a test class share the same database setup. But,with careful test design—such as proper data isolation, cleanup strategies, or using transactional rollbacks—these issues can be mitigated or entirely avoided.</p>
<h4 id="heading-more-care-needs-to-be-taken-around-indempotency">❌ <strong>More Care Needs To Be Taken Around Indempotency</strong></h4>
<p>“Indempotency” refers to the ability to run any test on its own in any order. If the test class is accessing data from the same areas, the assertions may fail when ran in certain orders than others. For example:</p>
<ul>
<li><p>Test_1 inserts a record.</p>
</li>
<li><p>Test_2 assumes the table is empty and asserts <code>QueryByName()</code> should return 1 record</p>
</li>
<li><p>Test_2 fails because Test_1 has already inserted its own record</p>
</li>
</ul>
<h2 id="heading-how-to-share-your-container-across-multiple-test-classes">How to Share Your Container Across Multiple Test Classes</h2>
<p>So we’ve covered a container per test and a container per test class. But what about sharing a container for multiple test classes? Well, it’s as simple as using the <code>ICollectionFixture</code> interface instead of <code>IClassFixture</code>, and it can be used like so:</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">CollectionDefinition(<span class="hljs-meta-string">"Database collection"</span>)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DatabaseCollection</span> : <span class="hljs-title">ICollectionFixture</span>&lt;<span class="hljs-title">TestClassFixture</span>&gt;
{
    <span class="hljs-comment">// This class has no code, </span>
    <span class="hljs-comment">// it’s just used to apply the [Collection] attribute to test classes.</span>
}
</code></pre>
<p>The <code>ICollectionFixture&lt;T&gt;</code> mechanism in xUnit automatically ties the fixture instance to all test classes marked with the <code>[Collection("Collection Name")]</code> attribute, for example:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> IntegrationTests;
<span class="hljs-keyword">using</span> Microsoft.Data.SqlClient;

[<span class="hljs-meta">Collection(<span class="hljs-meta-string">"Database collection"</span>)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">IntegrationFixtureTests</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _connectionString;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">IntegrationFixtureTests</span>(<span class="hljs-params">TestClassFixture testClassFixture</span>)</span>
    {
        _connectionString = testClassFixture.Container.GetConnectionString();
    }

    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Test_Database_Connection</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> conn = <span class="hljs-keyword">new</span> SqlConnection(_connectionString);
        <span class="hljs-keyword">await</span> conn.OpenAsync();

        Assert.True(conn.State == System.Data.ConnectionState.Open);
    }
}

[<span class="hljs-meta">Collection(<span class="hljs-meta-string">"Database collection"</span>)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AnotherIntegrationTest</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _connectionString;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AnotherIntegrationTest</span>(<span class="hljs-params">TestClassFixture testClassFixture</span>)</span>
    {
        _connectionString = testClassFixture.Container.GetConnectionString();
    }

    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">Another_Database_Test</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> conn = <span class="hljs-keyword">new</span> SqlConnection(_connectionString);
        <span class="hljs-keyword">await</span> conn.OpenAsync();

        Assert.True(conn.State == System.Data.ConnectionState.Open);
    }
}
</code></pre>
<p>Now you can group your integration tests, whether it be all read tests or all write tests – making your tests much more maintainable.</p>
<h2 id="heading-summary-of-approaches">Summary of Approaches:</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Approach</strong></td><td><strong>Container Creation</strong></td><td><strong>Best For</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>IAsyncLifetime</code> inside the test class</td><td><strong>One per test</strong></td><td>When a fresh DB state per test is needed, avoiding test contamination</td></tr>
<tr>
<td><code>IClassFixture&lt;T&gt;</code> with <code>IAsyncLifetime</code></td><td><strong>One per test class</strong></td><td>Faster execution, sharing DB instance across tests in a class</td></tr>
<tr>
<td><code>ICollectionFixture&lt;T&gt;</code> with <code>IAsyncLifetime</code></td><td><strong>One per multiple test classes</strong></td><td>Sharing a DB instance across different test classes</td></tr>
</tbody>
</table>
</div><h2 id="heading-how-to-create-multiple-containers">How to Create Multiple Containers</h2>
<p>Yes, you can create multiple containers which can host different images, making it perfect for when you have multiple systems you need to integrate with – for example Microsoft SQL Server and a Redis instance.</p>
<p>You can do this by calling the constructor of the relevant TestContainer package like below:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TestContainersFixture</span> : <span class="hljs-title">IAsyncLifetime</span>
{
    <span class="hljs-keyword">public</span> MsSqlContainer SqlContainer { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> RedisContainer RedisContainer { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InitializeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// SQL Server Container</span>
        SqlContainer = <span class="hljs-keyword">new</span> MsSqlBuilder()
            .WithImage(<span class="hljs-string">"mcr.microsoft.com/mssql/server:2022-latest"</span>)
            .WithPassword(<span class="hljs-string">"P@ssw0rd123"</span>)
            .WithPortBinding(<span class="hljs-number">1433</span>)
            .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">1433</span>))
            .Build();

        <span class="hljs-comment">// Redis Container</span>
        RedisContainer = <span class="hljs-keyword">new</span> RedisContainerBuilder()
            .WithImage(<span class="hljs-string">"redis:latest"</span>)
            .WithPortBinding(<span class="hljs-number">6379</span>)
            .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">6379</span>))
            .Build();

        <span class="hljs-keyword">await</span> Task.WhenAll(SqlContainer.StartAsync(), RedisContainer.StartAsync());
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DisposeAsync</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">await</span> Task.WhenAll(SqlContainer.DisposeAsync(), RedisContainer.DisposeAsync());
    }
}
</code></pre>
<p>And just like that, we have a SQL Server and a Redis instance ready to integrate test against.</p>
<h2 id="heading-how-to-make-your-setup-easier-with-custom-images">How to Make Your Setup Easier With Custom Images</h2>
<p>To make testing easier, and leverage the power of Docker and TestContainers, here’s a great tip. TestContainers fully supports using custom images, including pre-configured ones with seeded databases. Instead of defining everything in the test setup, you can build and use a custom Docker image that already contains the required schema and test data.</p>
<p>When creating your own custom package to use, you can:</p>
<ol>
<li>Upload your custom image to DockerHub and reference from there:</li>
</ol>
<pre><code class="lang-csharp"> SqlContainer = <span class="hljs-keyword">new</span> MsSqlBuilder()
            .WithImage(<span class="hljs-string">"your-dockerhub-username/custom-sql-image"</span>) 
            .WithPassword(<span class="hljs-string">"P@ssw0rd123"</span>)
            .WithPortBinding(<span class="hljs-number">1433</span>)
            .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">1433</span>))
            .Build();
</code></pre>
<ol start="2">
<li>Build your Docker image locally - f you're using a local image in TestContainers, you can simply reference the image name (e.g., <code>my-custom-sql-image</code>) in your code. TestContainers will first check your local Docker Desktop for the image before attempting to pull it from a registry like Docker Hub.</li>
</ol>
<pre><code class="lang-csharp">SqlContainer = <span class="hljs-keyword">new</span> MsSqlBuilder()
    .WithImage(<span class="hljs-string">"custom-sql-image"</span>) <span class="hljs-comment">// Reference your local image</span>
    .WithPassword(<span class="hljs-string">"P@ssw0rd123"</span>)
    .WithPortBinding(<span class="hljs-number">1433</span>)
    .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(<span class="hljs-number">1433</span>))
    .Build();
</code></pre>
<p>Having a pre-built image can speed up your tests especially in CI/CD pipelines, not to mention make them more readable by removing the seeding code.</p>
<p>To access your custom image in a CI/CD pipeline, you can upload it to DockerHub or GitHub Container Registry (GHCR) and access it from your tests. Build your DockerFile and push it to either system before accessing it in your tests.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Using TestContainers in .NET is a game-changer for integration testing. It’s a lightweight and automated way to manage external dependencies like databases, caching systems, and more. By using test containers in a test class, TestFixture, or ICollectionFixture, you can create cleaner, more reliable tests with isolated environments.</p>
<p>TestContainers can also save you money by eliminating the need for dedicated testing environments with long-lived dependencies. You can create and destroy them on the fly, or even integrate them into your CI/CD pipelines, especially in GitHub where Docker can be easily used.</p>
<p>As always I hope you’ve found this article helpful, and if you have any questions don’t hesitate to reach out on X / Twitter - <a target="_blank" href="https://x.com/grantdotdev">@grantdotdev</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use FakeLogger to Make Testing Easier In .Net ]]>
                </title>
                <description>
                    <![CDATA[ When writing unit tests in .NET, you may need to verify that methods are logging exceptions, errors, or other key information. You might think, No problem, I'll just mock ILogger using my favourite mocking library – for example Moq, NSubstitute, or F... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-fakelogger-to-make-testing-easier-in-net/</link>
                <guid isPermaLink="false">67b3b736d8f6ac012e312ac5</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Mon, 17 Feb 2025 22:24:54 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739486043718/2d1e6339-fb93-4719-a89a-5b29e30c2bfc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When writing unit tests in .NET, you may need to verify that methods are logging exceptions, errors, or other key information. You might think, <em>No problem, I'll just mock</em> <code>ILogger</code> <em>using my favourite mocking library</em> – for example Moq, NSubstitute, or FakeItEasy.</p>
<p>While <code>ILogger</code> itself is an interface and can be mocked, many of its commonly used logging methods (like <code>LogInformation()</code>, <code>LogError()</code>, and so on) are what’s called static or extension methods. Since static and extension methods can't be mocked directly, you often need a custom abstraction layer (LoggingService) or a decorator to pass to various other methods or services.</p>
<p>There is another much easier way though. In this article, I will show you how to use the relatively new feature available from .Net 8 upwards called <code>FakeLogger</code>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-tutorial-setup">Tutorial Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-the-logging-functionality">How to Test the Logging Functionality</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-fakelogger">How to Use FakeLogger</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-installing-fakelogger-and-fluentassertions">Installing FakeLogger and FluentAssertions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-using-the-fakelogger-class">Using the FakeLogger Class</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-collector">What Is Collector?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-useful-collector-properties">Useful Collector Properties</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-assert-that-structured-log-arguments-are-passed-correctly">How to Assert That Structured Log Arguments Are Passed Correctly</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-verify-that-a-message-has-been-called-at-any-time">How to Verify that a Message Has Been Called at Any Time</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ol>
<h2 id="heading-tutorial-setup">Tutorial Setup</h2>
<p>Let’s imagine you’ve created an online shopping ordering and invoicing service. The logical code tests have been completed, but you now need to test the logging functionality.</p>
<p>For this tutorial we’ll be using the <code>OrderService</code> and <code>InvoiceService</code> classes defined below. I’ve provided comments to illustrate where normally your logic would go, but as this isn’t relevant for the purpose of this tutorial, comments will suffice.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FakeLogger_Tutorial</span>;

<span class="hljs-function"><span class="hljs-keyword">public</span> class <span class="hljs-title">OrderService</span>(<span class="hljs-params">ILogger logger, IInvoiceService invoiceService</span>)</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessOrder</span>(<span class="hljs-params">Order order</span>)</span>
    {
        logger.LogInformation(<span class="hljs-string">"Processing order..."</span>);

        <span class="hljs-comment">// Order processing code goes here</span>

        logger.LogInformation(<span class="hljs-string">"Order processed successfully."</span>);

        invoiceService.SendInvoice(order);
    }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> class <span class="hljs-title">InvoiceService</span>(<span class="hljs-params">ILogger logger</span>) : IInvoiceService</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendInvoice</span>(<span class="hljs-params">Order order</span>)</span>
    {
        <span class="hljs-comment">// Dispatch order to shipping service</span>
        logger.LogInformation(<span class="hljs-string">"Order dispatched: {OrderId}"</span>, order.ID);

        <span class="hljs-comment">// Generate invoice code</span>

        SendEmail();
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Send email to customer</span>
        logger.LogInformation(<span class="hljs-string">"Sending invoice to customer"</span>);

        <span class="hljs-comment">// Perform email sending logic...</span>

        logger.LogInformation(<span class="hljs-string">"Email sent successfully."</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IInvoiceService</span>
{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">SendInvoice</span>(<span class="hljs-params">Order order</span>)</span>;
}
</code></pre>
<p>As well as a very basic <code>Order</code> and <code>Product</code> classes:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Order</span>
{
    <span class="hljs-keyword">public</span> Guid ID { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> required Guid CustomerId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">public</span> List&lt;Product&gt; Products = [];

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> TotalPrice =&gt; Products.Sum(x =&gt; x.Price);

    <span class="hljs-keyword">public</span> DateTime OrderDate { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>
{
    <span class="hljs-keyword">public</span> Guid ID { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> Price { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<h2 id="heading-how-to-test-the-logging-functionality">How to Test the Logging Functionality</h2>
<p>Like most aspects of coding, there are multiple ways to achieve this. The recommended approach is to mock the logger and assert against the mocked logger object rather than a concrete instance. This allows for controlled, isolated, and verifiable tests without relying on external dependencies or real logging behaviour – meaning cleaner and more maintainable tests.</p>
<p>You can do this using your preferred mocking library, such as <strong>Moq</strong>, <strong>FakeItEasy</strong>, or <strong>NSubstitute</strong>. You can learn more about these libraries and how to mock successfully in another tutorial I wrote, which you can find <a target="_blank" href="https://www.freecodecamp.org/news/explore-mocking-in-net/">here</a>.</p>
<p>Your initial thoughts may be to write tests like the below example using <code>Moq</code> and <code>XUnit</code> but this won’t work, and I’ll explain why.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> FakeLogger_Tutorial;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;
<span class="hljs-keyword">using</span> Moq;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">UnitTests</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">FailingTestCases</span>
{
    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">LogError_Should_Call_LogError</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Arrange</span>
        <span class="hljs-keyword">var</span> mockLogger = <span class="hljs-keyword">new</span> Mock&lt;ILogger&gt;();

        <span class="hljs-comment">// pass the mockedLogger to our service</span>
        <span class="hljs-keyword">var</span> orderService = <span class="hljs-keyword">new</span> OrderService(
            mockLogger.Object, 
            <span class="hljs-keyword">new</span> Mock&lt;IInvoiceService&gt;().Object
        );

        <span class="hljs-keyword">var</span> customerId = Guid.NewGuid();
        <span class="hljs-keyword">var</span> order = <span class="hljs-keyword">new</span> Order
        {
            ID = Guid.NewGuid(),
            CustomerId = customerId,
            Products = [<span class="hljs-keyword">new</span> Product { ID = Guid.NewGuid(), Name = <span class="hljs-string">"Ping pong balls"</span>, Price = <span class="hljs-number">1.00</span>M }],
            OrderDate = <span class="hljs-keyword">default</span>,
        };

        <span class="hljs-comment">// Act</span>
        orderService.ProcessOrder(order);      

        <span class="hljs-comment">// Assert</span>
        mockLogger.Verify(x =&gt; x.LogInformation(<span class="hljs-string">"Processing order..."</span>), Times.Once);
        mockLogger.Verify(x =&gt; x.LogInformation(<span class="hljs-string">"Order processed successfully."</span>), Times.Once);
    }
}
</code></pre>
<p>When you run this code, it <strong>will</strong> fail with the following error:</p>
<pre><code class="lang-markdown">System.NotSupportedException: 
Unsupported expression: x =&gt; x.LogInformation("Processing order...", new[] {  })
</code></pre>
<h3 id="heading-why-does-this-happen">Why Does This Happen?</h3>
<p>Mocking libraries struggle with static methods like <code>LogInformation</code> because they belong to the type itself, not an instance. Some tools, like JustMock, can handle this using advanced techniques like IL rewriting or shims, but these add complexity.</p>
<p>A common workaround is wrapping <code>ILogger</code> in a logging service for easier testing, along with benefits like abstraction and maintainability. But for a simpler approach, we’ll focus on the new <code>FakeLogger</code> class.</p>
<p>You could test ILogger using the <code>Verify</code> method in Moq, using some overly complicated, verbose methods like below. The test code will work, but it's a bit too complex and hard to read, especially at a glance.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> FakeLogger_Tutorial;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;
<span class="hljs-keyword">using</span> Moq;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">UnitTests</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">FailingTestCases</span>
{
    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">LogError_Should_Call_Logger_LogError</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Arrange</span>
        <span class="hljs-keyword">var</span> mockLogger = <span class="hljs-keyword">new</span> Mock&lt;ILogger&gt;();
        <span class="hljs-keyword">var</span> mockInvoiceService = <span class="hljs-keyword">new</span> Mock&lt;IInvoiceService&gt;();

        <span class="hljs-keyword">var</span> orderService = <span class="hljs-keyword">new</span> OrderService(
            mockLogger.Object, 
            mockInvoice.Object           
        );

        <span class="hljs-keyword">var</span> customerId = Guid.NewGuid();
        <span class="hljs-keyword">var</span> order = <span class="hljs-keyword">new</span> Order
        {
            ID = Guid.NewGuid(),
            CustomerId = customerId,
            Products = [<span class="hljs-keyword">new</span> Product { ID = Guid.NewGuid(), Name = <span class="hljs-string">"Ping pong balls"</span>, Price = <span class="hljs-number">1.00</span>M }],
            OrderDate = <span class="hljs-keyword">default</span>,
        };

        <span class="hljs-comment">// Act</span>
        orderService.ProcessOrder(order);

        <span class="hljs-comment">// Assert</span>
        mockLogger.Verify(logger =&gt; logger.Log(
                It.Is&lt;LogLevel&gt;(logLevel =&gt; logLevel == LogLevel.Information),
                It.Is&lt;EventId&gt;(eventId =&gt; eventId.Id == <span class="hljs-number">0</span>),
                It.Is&lt;It.IsAnyType&gt;((@object, @type) =&gt;
                    @object.ToString() == <span class="hljs-string">"Processing order..."</span>),
                It.IsAny&lt;Exception&gt;(),
                It.IsAny&lt;Func&lt;It.IsAnyType, Exception, <span class="hljs-keyword">string</span>&gt;&gt;()),
            Times.Once);
    }
}
</code></pre>
<h2 id="heading-how-to-use-fakelogger">How to Use FakeLogger</h2>
<p>With .NET 8, we can use the <code>FakeLogger</code> class to make tests clearer for other developers. If you haven’t upgraded yet, I highly recommend it—.NET 8 offers Long-Term Support (LTS) and unlocks many other useful features.</p>
<p>Microsoft defines the class as:</p>
<blockquote>
<p>This type is intended for use in unit tests. It captures all the log state to memory and lets you inspect it to validate that your code is logging what it should.</p>
</blockquote>
<p>In simple terms means that the FakeLogger acts as an in-memory collection of all the Logs and their associated data, meaning we can access these during out Unit Tests. It exposes all the extension methods we would find on the <code>ILogger</code> implementation, making it the perfect way to test our logging functionality.</p>
<h3 id="heading-installing-fakelogger-and-fluentassertions">Installing FakeLogger and FluentAssertions</h3>
<p>FluentAssertions is a great testing library which makes your code easier to test and easier to read. It focuses on using clearly named assertion functions, like <code>Should(), Have()</code> / <code>Be()</code>.</p>
<p>You can install using the Nuget Package Manager within your preferred IDE, or via the terminal with the following command:</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package FluentAssertions
</code></pre>
<p><strong>IMPORTANT: Do not exceed version 7.x.x of FluentAssertions, as v8 comes with a cost, whereas anything prior is free to use.</strong></p>
<p>Once installed, you will need to install <code>Microsoft.Extensions.Diagnostics.Testing</code> as before, using either the Package Console Manager, Terminal, or your preferred method.</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package Microsoft.Extensions.Diagnostics.Testing
</code></pre>
<h3 id="heading-using-the-fakelogger-class">Using the FakeLogger Class</h3>
<p>It is as simple as using any other class in C#. We can instantiate it like so:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.Diagnostics.Testing;

<span class="hljs-keyword">var</span> fakeLogger = <span class="hljs-keyword">new</span> FakeLogger();
</code></pre>
<p>Now, rather than passing the <code>mockLogger.Object</code> to our OrderService as before, we shall instead pass our new <code>fakeLoger</code> object like so:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> loggingService = <span class="hljs-keyword">new</span> OrderService(fakeLogger);
</code></pre>
<p>Below is an example of how we can use <code>FakeLogger</code> to check if an <em>Information</em> message was logged.</p>
<pre><code class="lang-csharp">    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OrderService_ProcessOrder_ShouldLogProgress</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Arrange</span>
        <span class="hljs-keyword">var</span> fakeLogger = <span class="hljs-keyword">new</span> FakeLogger();
        <span class="hljs-keyword">var</span> mockInvoiceService = <span class="hljs-keyword">new</span> Mock&lt;IInvoiceService&gt;();

        <span class="hljs-keyword">var</span> orderService = <span class="hljs-keyword">new</span> OrderService(
            fakeLogger,
            mockInvoiceService.Object
        );

        <span class="hljs-keyword">var</span> customerId = Guid.NewGuid();
        <span class="hljs-keyword">var</span> order = <span class="hljs-keyword">new</span> Order
        {
            ID = Guid.NewGuid(),
            CustomerId = customerId,
            Products = [<span class="hljs-keyword">new</span> Product { ID = Guid.NewGuid(), Name = <span class="hljs-string">"Ping pong balls"</span>, Price = <span class="hljs-number">1.00</span>M }],
            OrderDate = <span class="hljs-keyword">default</span>,
        };

        <span class="hljs-comment">// Act</span>
        orderService.ProcessOrder(order);

        <span class="hljs-comment">// Assert</span>
        fakeLogger.Collector.Count.Should().Be(<span class="hljs-number">2</span>);
        fakeLogger.Collector.LatestRecord.Level.Should().Be(LogLevel.Information);
        fakeLogger.Collector.LatestRecord.Message.Should().Be(<span class="hljs-string">"Order processed successfully."</span>);
    }
</code></pre>
<p>As you can see, it is much easier to read than the previous <code>Moq</code> implementation. The <code>FakeLogger</code> solution combined with <code>FluentAssertions</code> is much more concise and humanly readable to developers of all skillsets.</p>
<h3 id="heading-what-is-collector">What Is <code>Collector</code>?</h3>
<p>The <code>Collector</code> property in <code>FakeLogger</code> is an instance of <code>FakeLogCollector</code>, which collects and stores log information. It stores the messages in the same order they were called, making it easy to assert later.</p>
<h4 id="heading-purpose-of-the-collector-property"><strong>Purpose of the</strong> <code>Collector</code> Property</h4>
<ul>
<li><p>It <strong>stores all log messages</strong> captured by the <code>FakeLogger</code>.</p>
</li>
<li><p>You can access, filter, and assert against logs in your tests.</p>
</li>
<li><p>Useful when verifying structured logs or ensuring correct log levels.</p>
</li>
</ul>
<h3 id="heading-useful-collector-properties">Useful Collector Properties</h3>
<h3 id="heading-latestrecord"><code>LatestRecord</code></h3>
<p>There is more than one way in which you can access and assert logged messages. In the example above, we use the <code>LatestRecord</code> property. The <code>LatestRecord</code> property returns the last <code>FakeLogRecord</code> recorded. This comes from the internal property <code>Records</code>, returning the last record in the List.</p>
<p>The <code>FakeLogRecord</code> object has the following properties:</p>
<pre><code class="lang-csharp">Level
Id 
State
Exception
Message
Scopes
Category
LevelEnabled
Timestamp
</code></pre>
<p>We can therefore check any one of these properties in our assertions.</p>
<h3 id="heading-getsnapshot"><code>GetSnapshot()</code></h3>
<p>GetSnapshot() returns all log records collected.</p>
<ul>
<li><p>This method is useful when you want to inspect <strong>all</strong> logged messages, not just the most recent one.</p>
</li>
<li><p>It returns an <strong>immutable collection</strong>, ensuring that logs are not modified unexpectedly.</p>
</li>
</ul>
<p>As <code>GetSnapshot()</code> returns an immutable collection of messages. We can access these like any other collection of data, whilst also being able to use LINQ to filter, sort, and query the logs. This can be very useful when we would like to assert against the first, last, or any other logged message.</p>
<p>The following test utilises a concrete instance of <code>InvoiceService</code> as we wish to test the actual flow of logs, through both services.</p>
<pre><code class="lang-csharp">    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessOrder_ShouldLogMultipleMessages</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Arrange</span>
        <span class="hljs-keyword">var</span> fakeLog = <span class="hljs-keyword">new</span> FakeLogger();
        <span class="hljs-keyword">var</span> invoiceService = <span class="hljs-keyword">new</span> InvoiceService(fakeLog);
        <span class="hljs-keyword">var</span> orderService = <span class="hljs-keyword">new</span> OrderService(fakeLog, invoiceService);
        <span class="hljs-keyword">var</span> testOrder = <span class="hljs-keyword">new</span> Order
        {
            ID = Guid.NewGuid(),
            CustomerId = Guid.NewGuid(),
            Products =
            [<span class="hljs-meta">
                new Product { ID = Guid.NewGuid(), Name = <span class="hljs-meta-string">"Product 1"</span>, Price = 99.99m },
                new Product { ID = Guid.NewGuid(), Name = <span class="hljs-meta-string">"Product 2"</span>, Price = 199.99m }
            </span>],
        };

        <span class="hljs-comment">// Act</span>
        orderService.ProcessOrder(testOrder);

        <span class="hljs-comment">// Assert</span>
        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">0</span>].Message.Should().Be(<span class="hljs-string">"Processing order..."</span>);
        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">0</span>].Level.Should().Be(LogLevel.Information);

        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">1</span>].Message.Should().Be(<span class="hljs-string">"Order processed successfully."</span>);
        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">1</span>].Level.Should().Be(LogLevel.Information);

        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">2</span>].Message.Should().Be(<span class="hljs-string">$"Order dispatched: <span class="hljs-subst">{testOrder.ID}</span>"</span>);
        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">2</span>].Level.Should().Be(LogLevel.Information);

        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">3</span>].Message.Should().Be(<span class="hljs-string">"Sending invoice to customer"</span>);
        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">3</span>].Level.Should().Be(LogLevel.Information);

        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">4</span>].Message.Should().Be(<span class="hljs-string">"Email sent successfully."</span>);
        fakeLog.Collector.GetSnapshot()[<span class="hljs-number">4</span>].Level.Should().Be(LogLevel.Information);
    }
</code></pre>
<p>This test demonstrates how straightforward it is to assert that the logger captures messages in execution order with the correct <code>LogLevel</code> and message. It also highlights the readability of the test.</p>
<h2 id="heading-how-to-assert-that-structured-log-arguments-are-passed-correctly"><strong>How to Assert That Structured Log Arguments Are Passed Correctly</strong></h2>
<p>Structured logging allows us to pass objects and variables as arguments to log messages, providing richer and more searchable logs. In <code>ILogger</code>, we can pass an object like this:</p>
<pre><code class="lang-csharp">_logger.LogInformation(<span class="hljs-string">"Order processed: {OrderId}"</span>, order.ID);
</code></pre>
<p>By default, logging providers (like the built-in .NET <code>ILogger</code> provider) replace placeholders immediately in the final log message.</p>
<p>With the built-in <code>ILogger</code>, the log message is fully formatted at runtime, for example:</p>
<pre><code class="lang-csharp">_logger.LogInformation(<span class="hljs-string">"Order number {OrderId} dispatched"</span>, <span class="hljs-number">123</span>);
</code></pre>
<p><strong>Final log recorded is:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-string">"Order number 123 dispatched"</span>
</code></pre>
<p>This means that when retrieving logs in tests using the default log provider, we can only verify the final formatted string when using <code>FakeLogger</code> as it captures the fully rendered log message.</p>
<p><strong>Important:</strong> This differs from structured logging providers such as Serilog, where message templates and structured properties are stored separately. In Serilog, the <code>Message</code> column stores the original raw template string, while structured properties / objects are stored in a separate JSON field.</p>
<p>This doesn’t mean you can’t use <code>FakeLogger</code> with Serilog—you absolutely can. But when asserting logs, you must adjust your assertions depending on whether you're verifying the fully formatted message or structured properties.</p>
<p>If we log an order dispatch:</p>
<pre><code class="lang-csharp">logger.LogInformation(<span class="hljs-string">"Order dispatched: {OrderId}"</span>, order.ID);
</code></pre>
<p>Unlike Serilog, <code>FakeLogger</code> does not store <code>{OrderId}</code> as a separate property. Instead, it captures the fully formatted message:</p>
<pre><code class="lang-csharp"><span class="hljs-string">"Order dispatched: 550e8400-e29b-41d4-a716-446655440000"</span>
</code></pre>
<p>Thus, when testing with <code>FakeLogger</code>, we <strong>must</strong> assert against the final formatted string.</p>
<p>Even though <code>FakeLogger</code> does not store the original message template, it does capture structured data separately. This allows you to assert both:</p>
<ol>
<li><p>The final formatted message (since placeholders are replaced at runtime).</p>
</li>
<li><p>The structured data (objects or properties passed as arguments).</p>
</li>
</ol>
<p>The test below asserts the final formatted message, as well as a <code>StructuredState</code> object (the recorded structured log information).</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">InvoiceOrder_ShouldLog_StructuredLogInfo</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Arrange</span>
        <span class="hljs-keyword">var</span> fakeLogger = <span class="hljs-keyword">new</span> FakeLogger&lt;InvoiceService&gt;();
        <span class="hljs-keyword">var</span> service = <span class="hljs-keyword">new</span> InvoiceService(fakeLogger);
        <span class="hljs-keyword">var</span> testOrder = <span class="hljs-keyword">new</span> Order
        {
            ID = Guid.NewGuid(),
            CustomerId = Guid.NewGuid(),
            Products =
            [<span class="hljs-meta">
                new Product { ID = Guid.NewGuid(), Name = <span class="hljs-meta-string">"Product 1"</span>, Price = 99.99m },
                new Product { ID = Guid.NewGuid(), Name = <span class="hljs-meta-string">"Product 2"</span>, Price = 199.99m }
            </span>],
        };

        <span class="hljs-comment">// Act</span>
        service.SendInvoice(testOrder);

        <span class="hljs-comment">// Assert</span>
        fakeLogger.Collector.GetSnapshot()[<span class="hljs-number">0</span>].Message.Should().Be(<span class="hljs-string">$"Order dispatched: <span class="hljs-subst">{testOrder.ID}</span>"</span>);
        <span class="hljs-keyword">var</span> keyValuePairs = fakeLogger.Collector.GetSnapshot()[<span class="hljs-number">0</span>].StructuredState;

        <span class="hljs-keyword">var</span> orderIdProperty = keyValuePairs != <span class="hljs-literal">null</span> &amp;&amp; keyValuePairs
            .Any(x =&gt; x.Key == <span class="hljs-string">"OrderId"</span> &amp;&amp; x.Value == testOrder.ID.ToString());

        orderIdProperty.Should().BeTrue();
    }
</code></pre>
<h2 id="heading-how-to-verify-that-a-message-has-been-called-at-any-time">How to Verify That a Message Has Been Called at Any Time</h2>
<p>What if you want to test that a message or a set of messages are called <strong>anywhere</strong> within the call stack? You can easily do this with the help of LINQ (if you’re not familiar with LINQ you can read it about it in my other article <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-linq/">here</a>).</p>
<p>We don’t wish to assert that messages are sent in the correct order, just that the messages are logged. We can do this as follows:</p>
<pre><code class="lang-csharp">    [<span class="hljs-meta">Fact</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AllMessages_Should_BeSentInAnyOrder</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Arrange</span>
        <span class="hljs-keyword">var</span> testOrder = <span class="hljs-keyword">new</span> Order
        {
            ID = Guid.NewGuid(),
            CustomerId = Guid.NewGuid(),
            Products =
            [<span class="hljs-meta">
                new Product { ID = Guid.NewGuid(), Name = <span class="hljs-meta-string">"Product 1"</span>, Price = 99.99m },
                new Product { ID = Guid.NewGuid(), Name = <span class="hljs-meta-string">"Product 2"</span>, Price = 199.99m }
            </span>],
        };

        <span class="hljs-keyword">var</span> fakeLogger = <span class="hljs-keyword">new</span> FakeLogger();
        <span class="hljs-keyword">var</span> invoiceService = <span class="hljs-keyword">new</span> InvoiceService(fakeLogger);
        <span class="hljs-keyword">var</span> orderService = <span class="hljs-keyword">new</span> OrderService(fakeLogger, invoiceService);
        <span class="hljs-keyword">var</span> expectedMessages = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;
        {
            <span class="hljs-string">$"Order Dispatched: <span class="hljs-subst">{testOrder.ID}</span>"</span>,         
            <span class="hljs-string">"Processing order..."</span>,
            <span class="hljs-string">"Invoice sent"</span>
        };

        <span class="hljs-comment">// Act</span>
        orderService.ProcessOrder(testOrder);

        <span class="hljs-comment">// Assert</span>
        fakeLogger.Collector.GetSnapshot()
            .Select(x =&gt; x.Message)
            .Should().IntersectWith(expectedMessages);
    }
</code></pre>
<p>Here, we can utilise the power of LINQ and FluentAssertions to <code>Select</code> each message stored within the <code>Collector</code> property, and then assert that the array of messages can <code>IntersectWith</code> the expected messages.</p>
<p>The <code>IntersectWith</code> method asserts that the collection shares one or more items with the provided collection, a perfect fit for this kind of scenario where we don’t care about the order of logged messages – only that at some point they are logged.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Testing logging in .NET applications has traditionally been tricky because of extension methods in <code>ILogger</code>. But with .NET 8’s <code>FakeLogger</code>, we now have a cleaner, more readable, and efficient way to verify log messages in unit tests.</p>
<p>By using <code>FakeLogger</code> alongside <code>FluentAssertions</code>, we can simplify assertions, improve test readability, and ensure our logging behaviour is correctly implemented without the complexity of traditional mocking libraries.</p>
<p>Whether you're verifying message content, structured logs, or execution order, <code>FakeLogger</code> provides a robust solution that integrates seamlessly into modern .NET testing practices. If you haven't already, I highly recommend upgrading to .NET 8 to take full advantage of this powerful feature.</p>
<p>Hope you found this helpful! If you want to chat more, feel free to reach out on <a target="_blank" href="https://x.com/grantdotdev">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Collections in C# – Lists, Arrays, Dictionaries, and More ]]>
                </title>
                <description>
                    <![CDATA[ One of the first challenges beginners face when developing applications in C# is organising and managing data efficiently. Imagine keeping track of a list of items, mapping unique keys to values, or ensuring there are no duplicates in a collection – ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-collections-in-csharp/</link>
                <guid isPermaLink="false">6793a90ea69c4db6e76c194a</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ beginner ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Fri, 24 Jan 2025 14:51:58 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737729136643/4cc12d37-da1c-45f0-928f-fbe02d7fdf52.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>One of the first challenges beginners face when developing applications in C# is organising and managing data efficiently. Imagine keeping track of a list of items, mapping unique keys to values, or ensuring there are no duplicates in a collection – these are all common tasks where choosing the right data structure can make a big difference.</p>
<p>C# provides a rich set of built-in data structures, such as <strong>lists</strong>, <strong>dictionaries</strong>, and more, making it easier to work with data differently. Each structure has strengths and is optimised for specific scenarios, so understanding their differences is key to writing clean, efficient, and maintainable code.</p>
<p>In this tutorial, we’ll explore:</p>
<ul>
<li><p><strong>Lists</strong>: Your go-to for dynamic, ordered collections where elements can grow and shrink effortlessly.</p>
</li>
<li><p><strong>Arrays</strong>: The efficient choice for fixed-size collections with predictable memory usage and blazing-fast indexing.</p>
</li>
<li><p><strong>Dictionaries</strong>: Perfect for quick lookups and managing key-value pairs with unmatched speed and clarity.</p>
</li>
<li><p><strong>Stacks</strong>: Ideal for last-in-first-out (LIFO) operations, like tracking history or nested structures.</p>
</li>
<li><p><strong>Queues</strong>: Best for first-in-first-out (FIFO) tasks, like processing jobs or managing sequential workflows.</p>
</li>
<li><p><strong>HashSets:</strong> The choice for collections where uniqueness matters and fast lookups are key.</p>
</li>
</ul>
<p>By the end of this guide, you'll understand the differences between these structures and be equipped to choose the right one for your next project.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-arrays">Arrays in C#</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lists">Lists in C#</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-dictionaries">Dictionaries in C#</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hashsets">HashSets in C#</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-queues">Queues in C#</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-stacks">Stacks in C#</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-common-problems">Common Problems</a></p>
</li>
</ol>
<p>For some of the following examples, you’ll need the <code>Animal</code> record below:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">Animal</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> Age, <span class="hljs-keyword">string</span> Name, <span class="hljs-keyword">int</span> Legs, <span class="hljs-keyword">string</span> Sound</span>)</span>;
</code></pre>
<h2 id="heading-arrays">Arrays</h2>
<p>An <strong>array</strong> in C# is a fixed-size collection of elements. Arrays are indexed, and their size is set when they are created unlike Lists and other collections. Once defined, the size of an array cannot be changed, making the memory efficient with a low overhead.</p>
<h3 id="heading-single-dimension-arrays">Single-Dimension Arrays</h3>
<p>Arrays are zero-index based, meaning their index begins at 0, rather than 1. If you’re not familiar, an index is a pointer to help you find an item.</p>
<p>For example, if you have 5 names in an Array, the first name is index [0], and the last name would be at index [4].</p>
<p>Arrays are great in scenarios where low-level performance is critical, as they have very little overhead due to their lack of metadata (additional attached information).</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">int</span>[] numbers = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[] { <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span> };

<span class="hljs-keyword">foreach</span>(<span class="hljs-keyword">var</span> number <span class="hljs-keyword">in</span> numbers){
    Console.Write(number);
}
<span class="hljs-comment">//Ouput</span>
<span class="hljs-comment">// 1 2 3 4 5</span>
</code></pre>
<p>In the above example, we instantiate an array with its values (thus giving it a fixed length). But we can assign values after the array is created by using index assignment.</p>
<p><em>Note: You must still specify the size of the array at the time of creation, as the code needs to know the fixed size of the Array.</em></p>
<pre><code class="lang-csharp"><span class="hljs-comment">// create an empty array of 20 indexes</span>
<span class="hljs-keyword">var</span> numbers = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">20</span>];

<span class="hljs-comment">// loop over available indexes and assign `i` </span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; numbers.Length; i++)
{
    numbers[i] = i + <span class="hljs-number">1</span>;
}

<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> number <span class="hljs-keyword">in</span> numbers)
{
    Console.Write(<span class="hljs-string">$" <span class="hljs-subst">{number}</span>"</span>);
}
<span class="hljs-comment">// Output</span>
<span class="hljs-comment">//  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20</span>
</code></pre>
<h3 id="heading-multi-dimensional-arrays">Multi-Dimensional Arrays</h3>
<p>Arrays can also be multi-dimensional (for example, rows and columns), meaning they can hold two values. This makes them perfect for building grid-like structures.  </p>
<p>Unlike a jagged array, where each element is an array that can have different lengths, a multidimensional array is a matrix-like structure where each dimension has a fixed size.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Create a 2D multi-dimensional array to represent a chessboard</span>

<span class="hljs-keyword">string</span>[,] chessBoard = <span class="hljs-keyword">new</span> <span class="hljs-keyword">string</span>[<span class="hljs-number">8</span>, <span class="hljs-number">8</span>];

<span class="hljs-comment">// Creating the starting positions of a Chessboard</span>
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>] = <span class="hljs-string">"Rook"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>] = <span class="hljs-string">"Knight"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">2</span>] = <span class="hljs-string">"Bishop"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">3</span>] = <span class="hljs-string">"Queen"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">4</span>] = <span class="hljs-string">"King"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">5</span>] = <span class="hljs-string">"Bishop"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">6</span>] = <span class="hljs-string">"Knight"</span>;
chessBoard[<span class="hljs-number">0</span>, <span class="hljs-number">7</span>] = <span class="hljs-string">"Rook"</span>;

chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">0</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">3</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">4</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">5</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">6</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">1</span>, <span class="hljs-number">7</span>] = <span class="hljs-string">"Pawn"</span>;

chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">0</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">1</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">2</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">3</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">4</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">5</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">6</span>] = <span class="hljs-string">"Pawn"</span>;
chessBoard[<span class="hljs-number">6</span>, <span class="hljs-number">7</span>] = <span class="hljs-string">"Pawn"</span>;

chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">0</span>] = <span class="hljs-string">"Rook"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">1</span>] = <span class="hljs-string">"Knight"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">2</span>] = <span class="hljs-string">"Bishop"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">3</span>] = <span class="hljs-string">"Queen"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">4</span>] = <span class="hljs-string">"King"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">5</span>] = <span class="hljs-string">"Bishop"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">6</span>] = <span class="hljs-string">"Knight"</span>;
chessBoard[<span class="hljs-number">7</span>, <span class="hljs-number">7</span>] = <span class="hljs-string">"Rook"</span>;


<span class="hljs-comment">// Print the chessboard</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> row = <span class="hljs-number">0</span>; row &lt; <span class="hljs-number">8</span>; row++)
{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> col = <span class="hljs-number">0</span>; col &lt; <span class="hljs-number">8</span>; col++)
    {
        <span class="hljs-keyword">string</span> piece = chessBoard[row, col] ?? <span class="hljs-string">"Empty"</span>;
        Console.Write(<span class="hljs-string">$"<span class="hljs-subst">{piece}</span>\t"</span>);
    }
    Console.WriteLine();
}
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-bash">Rook    Knight  Bishop  Queen   King    Bishop  Knight  Rook    
Pawn    Pawn    Pawn    Pawn    Pawn    Pawn    Pawn    Pawn    
Empty   Empty   Empty   Empty   Empty   Empty   Empty   Empty   
Empty   Empty   Empty   Empty   Empty   Empty   Empty   Empty   
Empty   Empty   Empty   Empty   Empty   Empty   Empty   Empty   
Empty   Empty   Empty   Empty   Empty   Empty   Empty   Empty   
Pawn    Pawn    Pawn    Pawn    Pawn    Pawn    Pawn    Pawn    
Rook    Knight  Bishop  Queen   King    Bishop  Knight  Rook
</code></pre>
<h3 id="heading-jagged-array">Jagged Array</h3>
<p>Welcome to inception. A <strong>jagged array</strong> in C# is an array of arrays, where each "inner" array can have a different length.</p>
<p>Unlike multi-dimensional arrays, jagged arrays are not rectangular, meaning the rows can have varying sizes.</p>
<p>A usage example could be building a Calendar app. Below is a basic usage outputting the days of each month in the year:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">int</span>[][] daysInMonths = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">12</span>][];

<span class="hljs-comment">// Initialize each month with its corresponding number of days</span>
daysInMonths[<span class="hljs-number">0</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// January</span>
daysInMonths[<span class="hljs-number">1</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">28</span>]; <span class="hljs-comment">// February (non-leap year)</span>
daysInMonths[<span class="hljs-number">2</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// March</span>
daysInMonths[<span class="hljs-number">3</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">30</span>]; <span class="hljs-comment">// April</span>
daysInMonths[<span class="hljs-number">4</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// May</span>
daysInMonths[<span class="hljs-number">5</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">30</span>]; <span class="hljs-comment">// June</span>
daysInMonths[<span class="hljs-number">6</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// July</span>
daysInMonths[<span class="hljs-number">7</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// August</span>
daysInMonths[<span class="hljs-number">8</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">30</span>]; <span class="hljs-comment">// September</span>
daysInMonths[<span class="hljs-number">9</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// October</span>
daysInMonths[<span class="hljs-number">10</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">30</span>]; <span class="hljs-comment">// November</span>
daysInMonths[<span class="hljs-number">11</span>] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">31</span>]; <span class="hljs-comment">// December</span>

<span class="hljs-comment">// Print the number of days in each month</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> month = <span class="hljs-number">0</span>; month &lt; daysInMonths.Length; month++)
{
    Console.WriteLine(<span class="hljs-string">$"Month <span class="hljs-subst">{month + <span class="hljs-number">1</span>}</span>: <span class="hljs-subst">{daysInMonths[month].Length}</span> days"</span>);
}
</code></pre>
<p>You should use an <code>Array</code> in:</p>
<ul>
<li><p><strong>Performance-critical applications</strong> where memory overhead and speed matter.</p>
</li>
<li><p><strong>Fixed data sets</strong> where the size will not change.</p>
</li>
<li><p><strong>Multi-dimensional data</strong>, for example, graph coordinates (x, y)</p>
</li>
</ul>
<h2 id="heading-lists">Lists</h2>
<p>A <code>List&lt;T&gt;</code> in C# is a resizable collection of items of the same type, signaled above by the letter <code>T</code>. It allows adding, removing, and accessing items by index. Unlike arrays, lists grow dynamically as needed.  </p>
<p>Commonly used for sequential data, they support <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-linq/">LINQ</a> queries and various utility methods for data manipulation.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> animals = <span class="hljs-keyword">new</span> List&lt;Animal&gt;()
{
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">10</span>, <span class="hljs-string">"Dog"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Woof"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">5</span>, <span class="hljs-string">"Cat"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Meow"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">2</span>, <span class="hljs-string">"Lion"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Roar"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">6</span>, <span class="hljs-string">"Giraffe"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Trumpet"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">15</span>, <span class="hljs-string">"Red-Panda"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Squeak"</span>)    
};

animals.Add(<span class="hljs-keyword">new</span> Animal(<span class="hljs-number">2</span>, <span class="hljs-string">"Hamster"</span>,<span class="hljs-number">4</span>,<span class="hljs-string">"Squeak"</span>));
animals.Remove(x=&gt;x.Sound == <span class="hljs-string">"Meow"</span>); <span class="hljs-comment">// Remove all squeaking animals</span>
</code></pre>
<p>Lists are a highly versatile data structure, where the order of items remains the same order in which they are added or removed (no manipulation. For example, whenever you call <code>.Add()</code> a method on a list, it will append the item to the list, and the order stays the same as before but with the additional animal.</p>
<p>You can modify the data (for example, filter, map, or sort) before sending lists to other areas of your application thanks to the extensive utility methods available in the <code>List&lt;T&gt;</code> class.</p>
<h2 id="heading-dictionaries">Dictionaries</h2>
<p>Dictionaries work just like the term we know in the English language.</p>
<p>We have a key (a lookup term) and a value (the mapped object or data). Because of this, you might hear the term 'key-value pair' when referring to dictionaries.</p>
<p>Dictionaries are best used to efficiently retrieve data based on a unique identifier, such as an ID, name, or other uniquely identifying fields. They ensure their unique keys are ideal for scenarios requiring optimal performance without iterative searching.  </p>
<p>I recommend using dictionaries when the order of elements is unimportant and you need to represent relationships, such as mapping countries to capitals, products to prices, or people to addresses.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> animalDictionary = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-keyword">string</span>, Animal&gt;()
{
    { <span class="hljs-string">"Dog"</span>, <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">10</span>, <span class="hljs-string">"Dog"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Woof"</span>) },
    { <span class="hljs-string">"Cat"</span>, <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">5</span>, <span class="hljs-string">"Cat"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Meow"</span>) },
    { <span class="hljs-string">"Elephant"</span>, <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">8</span>, <span class="hljs-string">"Elephant"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Trumpet"</span>) },
    { <span class="hljs-string">"Lion"</span>, <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">2</span>, <span class="hljs-string">"Lion"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Roar"</span>) },
    { <span class="hljs-string">"Giraffe"</span>, <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">6</span>, <span class="hljs-string">"Giraffe"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Trumpet"</span>) },
};
<span class="hljs-comment">// Add</span>
animalDictionary.Add(<span class="hljs-string">"Red panda"</span>, <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">2</span>, <span class="hljs-string">"Red Panda"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Squeaker"</span>));

<span class="hljs-comment">// Remove</span>
animalDictionary.Remove(<span class="hljs-string">"Cat"</span>);

<span class="hljs-comment">//Get</span>
<span class="hljs-keyword">var</span> giraffe = animalDictionary[<span class="hljs-string">"Giraffe"</span>];
</code></pre>
<h2 id="heading-hashsets">HashSets</h2>
<p>A <code>HashSet&lt;T&gt;</code> is a collection in C# that stores unique elements. It uses a hash-based implementation to ensure very efficient lookups, additions, and deletions. This means it uses hash functions to quickly map keys to values, you can read more about that here.</p>
<p>Duplicate elements are automatically ignored.</p>
<p>How does this differ from a Dictionary? HashSets don't have keys like Dictionaries. Instead, they store values directly and are accessed by iterating over the elements using a <code>foreach</code> loop or LINQ queries.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> animalHashSet = <span class="hljs-keyword">new</span> HashSet&lt;Animal&gt;()
{
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">3</span>, <span class="hljs-string">"Lion"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Roar"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">5</span>, <span class="hljs-string">"Tiger"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Roar"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">2</span>, <span class="hljs-string">"Elephant"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Trumpet"</span>),
    <span class="hljs-keyword">new</span> Animal(<span class="hljs-number">1</span>, <span class="hljs-string">"Giraffe"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Neigh"</span>)
};
<span class="hljs-comment">// Add</span>
animalHashSet.Add(<span class="hljs-keyword">new</span> Animal(<span class="hljs-number">3</span>, <span class="hljs-string">"Lion"</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Roar"</span>));
<span class="hljs-comment">// Remove</span>
animalHashSet.Remove(x=&gt;x.Sound == <span class="hljs-string">"Neigh"</span>);
<span class="hljs-comment">// Get</span>
animalHashSet.FirstOrDefault(x=&gt;x.Name == <span class="hljs-string">"Elephant"</span>);
</code></pre>
<p>Above, we create a <code>HashSet&lt;Animal&gt;</code> and attempt to add a duplicate object. You may expect this to throw an error, as we know HashSets can only store unique values. But instead it handles it quite beautifully and simply doesn’t add the duplicate object, so the output is:</p>
<pre><code class="lang-bash">Animal { Age = 3, Name = Lion, Legs = 4, Sound = Roar }
Animal { Age = 5, Name = Tiger, Legs = 4, Sound = Roar }
Animal { Age = 2, Name = Elephant, Legs = 4, Sound = Trumpet }
</code></pre>
<h2 id="heading-queues">Queues</h2>
<p>Queues work in just the same way as a queue does in everyday life, with a first-in, first-out approach.</p>
<p><code>Queue&lt;T&gt;</code> does not implement the ICollection interface like Dictionaries and Lists, meaning it doesn't have an <strong>Add()</strong> method. This means you cannot add elements to the Queue whilst instantiating. It also means you cannot use the <strong>Add()</strong> method to add items – instead, you use the <strong>Enqueue()</strong> method.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> arc = <span class="hljs-keyword">new</span> Queue&lt;<span class="hljs-keyword">string</span>&gt;();
arc.Enqueue(<span class="hljs-string">"2 Lions"</span>);
arc.Enqueue(<span class="hljs-string">"2 Tigers"</span>);
arc.Enqueue(<span class="hljs-string">"2 Bears"</span>);

<span class="hljs-comment">// Peek method allows to peek at the front of the queue</span>
Console.WriteLine(<span class="hljs-string">"Front of the Queue: "</span> + arc.Peek());

<span class="hljs-comment">// Output</span>
<span class="hljs-comment">// Front of the Queue: 2 Lions</span>

Console.WriteLine(<span class="hljs-string">$"Processing: <span class="hljs-subst">{arc.Dequeue()}</span>"</span>); <span class="hljs-comment">// Output: 2 Lions</span>
Console.WriteLine(<span class="hljs-string">$"Processing: <span class="hljs-subst">{arc.Dequeue()}</span>"</span>); <span class="hljs-comment">// Output: 2 Tigers</span>
</code></pre>
<p>The <code>Dequeue</code> method not only returns the next item in the queue but also removes the item from the queue as expected. You can also clear the queue using the <code>Clear()</code> method.</p>
<h2 id="heading-stacks">Stacks</h2>
<p>Stacks work oppositely to <code>Queue&lt;T&gt;</code>, in that instead of first-in-first-out, they work on a last-in-first-out mechanic.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> stack = <span class="hljs-keyword">new</span> Stack&lt;<span class="hljs-keyword">int</span>&gt;();
stack.Push(<span class="hljs-number">1</span>);
stack.Push(<span class="hljs-number">2</span>);
stack.Push(<span class="hljs-number">3</span>);
stack.Push(<span class="hljs-number">4</span>);
stack.Push(<span class="hljs-number">5</span>);

<span class="hljs-comment">// iterate over the Stack</span>
<span class="hljs-keyword">foreach</span>(<span class="hljs-keyword">var</span> number <span class="hljs-keyword">in</span> stack )
{
    Console.WriteLine(number);
}

<span class="hljs-comment">// Output</span>
<span class="hljs-comment">// 5 4 3 2 1</span>
</code></pre>
<p>You may think looping through the items in a <code>Stack</code> would work the same as a List or Queue and would still print them out in order of going in. But the system knows it’s a stack, and so it enumerates the items in reverse order of how they were added – that is, the most recently added element (<code>5</code>) is returned first.</p>
<p>You can also utilise the <code>Pop()</code> method which will return the last item in the collection, and remove it at the same time.</p>
<h2 id="heading-common-problems">Common Problems</h2>
<p>When using various collections, you will more than likely come across common problems, such as <code>KeyNotFoundException</code> when using dictionaries, <code>IndexOutOfRangeException</code> on lists/arrays, or <code>InvalidOperationException</code> when modifying a collection during iteration.</p>
<h3 id="heading-keynotfoundexception"><code>KeyNotFoundException</code></h3>
<p><strong>Scenario:</strong> You try to access a Dictionary key that doesn’t exist in the Dictionary. This will result in a <code>KeyNotFoundException</code>, and error.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> dictionary = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt;()
{
    { <span class="hljs-string">"Morning"</span>, <span class="hljs-string">"Good Morning"</span> },
    { <span class="hljs-string">"Afternoon"</span>, <span class="hljs-string">"Good afternoon"</span> },
    { <span class="hljs-string">"Evening"</span>, <span class="hljs-string">"Good evening"</span> },
    { <span class="hljs-string">"Night"</span>, <span class="hljs-string">"Good night"</span> },
};

<span class="hljs-keyword">var</span> message = dictionary[<span class="hljs-string">"Dusk"</span>];

Console.WriteLine(message);

<span class="hljs-comment">// Output</span>
<span class="hljs-comment">//Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'Dusk' was not present in the dictionary.</span>
</code></pre>
<p><strong>Solution:</strong> I recommend using the <code>TryGetValue</code> function, which will handle it gracefully and return the item as an <code>out</code> parameter (if it can be found, otherwise the default value).</p>
<p><code>TryGetValue</code> returns a boolean to show whether it could or couldn’t find the provided key. This boolean value can then be utilised to determine functionality based on successful retrieval or not, rather than checking the output parameter, for example (if it is null/empty or not).</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> dictionary = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt;()
{
    { <span class="hljs-string">"Morning"</span>, <span class="hljs-string">"Good Morning"</span> },
    { <span class="hljs-string">"Afternoon"</span>, <span class="hljs-string">"Good afternoon"</span> },
    { <span class="hljs-string">"Evening"</span>, <span class="hljs-string">"Good evening"</span> },
    { <span class="hljs-string">"Night"</span>, <span class="hljs-string">"Good night"</span> },
};

<span class="hljs-keyword">var</span> input = Console.ReadLine(); <span class="hljs-comment">// Dusk</span>

dictionary.TryGetValue(input, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> message);
Console.WriteLine(<span class="hljs-string">$"`Message:<span class="hljs-subst">{message}</span>`"</span>);
<span class="hljs-comment">// Ouput = `Message ` (blank message as default string value is empty string</span>

<span class="hljs-comment">//or check if was able to retrieve and access output if it was</span>
<span class="hljs-keyword">if</span>(dictionary.TryGetValue(input,<span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> m)){
    Console.WriteLine(message);
}
</code></pre>
<h3 id="heading-indexoutofrangeexception-listsarrays"><code>IndexOutOfRangeException</code> (Lists/Arrays):</h3>
<p><strong>Scenario</strong>: Trying to access an index that’s outside the valid range of a list or array.  </p>
<p>As we know, Arrays are 0 index-based, so trying to access an index of [5] on an Array of 5 items will throw the <code>IndexOutOfRangeException</code>.</p>
<p><strong>Solutions:</strong></p>
<ol>
<li>Ensure the index is within bounds using <code>list.Count</code> or <code>array.Length</code> before access.</li>
</ol>
<ol start="2">
<li>Use the <code>ElementAtOrDefault()</code> method. If it can’t access an item at the given index, it will return the default value, which can then be handled accordingly.</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> names = <span class="hljs-keyword">new</span> <span class="hljs-keyword">string</span>[]
{
    <span class="hljs-string">"Tony"</span>, <span class="hljs-string">"Clint"</span>, <span class="hljs-string">"Bob"</span>, <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"Lisa"</span>
};

<span class="hljs-keyword">var</span> name = names.ElementAtOrDefault(<span class="hljs-number">6</span>);
Console.WriteLine(name ?? <span class="hljs-string">"Name not found."</span>);
</code></pre>
<h3 id="heading-invalidoperationexception-iterating-collections"><code>InvalidOperationException</code> (Iterating Collections):</h3>
<p><strong>Scenario</strong>: Modifying a collection (for example, adding or removing items) while iterating over it with a <code>foreach</code> loop will throw an <code>InvalidOperationException</code> because you're trying to remove an item from the list while iterating over it with a <code>foreach</code> loop.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> myList = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt; { <span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Banana"</span>, <span class="hljs-string">"Cherry"</span>, <span class="hljs-string">"Banana"</span> };

<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> item <span class="hljs-keyword">in</span> myList)
{
    <span class="hljs-keyword">if</span> (item == <span class="hljs-string">"Banana"</span>)
    {
        myList.Remove(item); <span class="hljs-comment">// Throws InvalidOperationException</span>
    }
}
</code></pre>
<h4 id="heading-why-this-happens"><strong>Why This Happens:</strong></h4>
<ul>
<li><p>The <code>foreach</code> loop maintains an internal enumerator for the collection.</p>
</li>
<li><p>Modifying the collection (for example, adding/removing items) invalidates the enumerator, which causes the runtime to throw an <code>InvalidOperationException</code>.</p>
</li>
</ul>
<p><strong>Solution 1: Use a</strong> <code>for</code> <strong>Loop</strong></p>
<p>You can use a <code>for</code> loop with an index to safely modify the list during iteration:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> fruits = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt; { <span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Banana"</span>, <span class="hljs-string">"Cherry"</span>, <span class="hljs-string">"Banana"</span> };

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; fruits; i++)
{
    <span class="hljs-keyword">if</span> (fruits[i] == <span class="hljs-string">"Banana"</span>)
    {
        fruits.RemoveAt(i);
        <span class="hljs-comment">// Adjust the index to account for the removed item</span>
        i--; 
    }
}
Console.WriteLine(<span class="hljs-keyword">string</span>.Join(<span class="hljs-string">", "</span>, fruits)); 
<span class="hljs-comment">// Output: Apple, Cherry</span>
</code></pre>
<p><strong>Solution 2: Iterate Over a Copy</strong></p>
<p>Another approach is to iterate over a copy of the list using <code>ToList()</code>. This way, you’re not directly iterating over the original collection, so modifications won’t affect the loop.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> originalList = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt; { <span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Banana"</span>, <span class="hljs-string">"Cherry"</span>, <span class="hljs-string">"Banana"</span> };

<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> item <span class="hljs-keyword">in</span> originalList.ToList()) <span class="hljs-comment">// Create a copy</span>
{
    <span class="hljs-keyword">if</span> (item == <span class="hljs-string">"Banana"</span>)
    {
        originalList.Remove(item); <span class="hljs-comment">// Safe removal</span>
    }
}
Console.WriteLine(<span class="hljs-keyword">string</span>.Join(<span class="hljs-string">", "</span>, originalList)); 
<span class="hljs-comment">// Output: Apple, Cherry</span>
</code></pre>
<p><strong>Solution 3: Use LINQ to Filter</strong></p>
<p>If you only want to remove items based on a condition, you can use LINQ to create a new filtered list:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> fruits = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt; { <span class="hljs-string">"Apple"</span>, <span class="hljs-string">"Banana"</span>, <span class="hljs-string">"Cherry"</span>, <span class="hljs-string">"Banana"</span> };

fruits = fruits.Where(item =&gt; item != <span class="hljs-string">"Banana"</span>).ToList(); <span class="hljs-comment">// Filter out "Banana"</span>

Console.WriteLine(<span class="hljs-keyword">string</span>.Join(<span class="hljs-string">", "</span>, fruits)); 
<span class="hljs-comment">// Output: Apple, Cherry</span>
</code></pre>
<h2 id="heading-closing-thoughts">Closing Thoughts</h2>
<p>In this article, you’ve learned about many of the common Data Structures for storing multiple objects and values.</p>
<p>Whether you're storing data in a fixed-size array, managing a dynamic list, working with first-in-first-out queues, last-in-first-out stacks, or key-value pair dictionaries, knowing when and how to use each collection is key to becoming a confident and proficient C# developer.</p>
<p>Mastering these concepts will not only improve your ability to handle data effectively but also lay the groundwork for more advanced topics in data structures and algorithms. Combining these data structures with LINQ can provide some performant and easy-to-use mechanics. To learn more about LINQ you can check out my article <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-linq/">here</a>.  </p>
<p>As you continue your coding journey, keep experimenting with these collections, apply them in real-world scenarios, and deepen your understanding of their inner workings.</p>
<p>As always should you wish to discuss this article further, any other coding-related problems, or hear about other articles I’m writing, drop me a follow on <a target="_blank" href="https://x.com/grantdotdev">X(Twitter)</a>  </p>
<p>Happy coding! 😊</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The C# Class Handbook – Types of Classes with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ Classes are the fundamental building blocks of object-oriented programming in C#. They allow you to create reusable and modular code by grouping related data and functions. Different types of classes serve various purposes. For instance, organizing y... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/classes-in-c-sharp-handbook-with-examples/</link>
                <guid isPermaLink="false">67659959cfcbe6eba5ecf6dc</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dotnet ]]>
                    </category>
                
                    <category>
                        <![CDATA[ classes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isaiah Clifford Opoku ]]>
                </dc:creator>
                <pubDate>Fri, 20 Dec 2024 16:20:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734711601436/b4de90be-1d93-4d8d-a4ed-ae09b192ef5c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Classes are the fundamental building blocks of object-oriented programming in C#. They allow you to create reusable and modular code by grouping related data and functions.</p>
<p>Different types of classes serve various purposes. For instance, organizing your logic to make your code easier to navigate is helpful when building an application.</p>
<p>You can group or separate your code into classes, and through inheritance, you can utilize different classes as needed. Classes help encapsulate your code, enabling you to reuse your logic in other application parts. Classes have many functionalities, and we will explore some of them in detail.</p>
<p>In this guide, we'll explore various types of classes in C# and how you can use them to create efficient and maintainable code.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>Before we proceed, you should have the following:</p>
<ol>
<li><p><strong>Basic knowledge of C#</strong>: you should understand C# syntax and basic programming constructs like variables, loops, and conditionals.</p>
</li>
<li><p><strong>Familiarity with Object-Oriented Programming (OOP) concepts</strong>: you should know how to work with classes, objects, inheritance, polymorphism, encapsulation, and abstraction.</p>
</li>
<li><p><strong>Familiarity with access modifiers</strong>: you should understand public, private, internal, and protected access modifiers.</p>
</li>
<li><p><strong>Experience with C# IDE/Environment</strong>: you should be able to write and run C# programs using an IDE like Visual Studio.</p>
</li>
</ol>
<p>If you want to learn more about C#, you can check out my YouTube channel: <a target="_blank" href="https://www.youtube.com/@CliffTech">CliffTech</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-static-classes-in-c-sharp">Static Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-sealed-classes-in-c-sharp">Sealed Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-concrete-classes-in-c-sharp">Concrete Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-abstract-classes-in-c-sharp">Abstract Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-singleton-classes-in-c-sharp">Singleton Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-generic-classes-in-c-sharp">Generic Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-internal-classes-in-c-sharp">Internal Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-nested-classes-in-c-sharp">Nested Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-partial-classes-in-c-sharp">Partial Classes in C Sharp</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>The first type of class we’ll discuss is the Static Class. Let’s dive in.</p>
<h2 id="heading-static-classes-in-c-sharp">Static Classes in C Sharp</h2>
<p>Static classes are a special type of class in C# designed to provide a collection of related utility methods and properties that do not rely on instance data.</p>
<p>Static classes in C# are a unique type of class designed to house a collection of related utility methods and properties that don't depend on instance data.</p>
<p>Unlike regular classes, static classes cannot be instantiated, and they exclusively contain static members. This characteristic means they cannot be inherited, making them perfect for organizing stateless methods that don't require the features of object-oriented programming.</p>
<p>In essence, when we refer to stateless grouping, it implies that there's no need to create an instance to call a static method – you can simply use the class or method name directly. This approach provides a clear and efficient way to manage utility functions, enhancing code organization and accessibility.</p>
<h3 id="heading-example-of-a-static-class-in-c">Example of a Static Class in C</h3>
<p>Here's an example of a static class in C#:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">StaticClasses</span>
{
<span class="hljs-comment">// Define a static class</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MathUtils</span>
    {
        <span class="hljs-comment">// Static method to add two numbers</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Add</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b</span>)</span>
        {
            <span class="hljs-keyword">return</span> a + b;
        }

        <span class="hljs-comment">// Static method to subtract two numbers</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Subtract</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b</span>)</span>
        {
            <span class="hljs-keyword">return</span> a - b;
        }

       <span class="hljs-comment">// Static method to multiply two numbers</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Multiply</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b</span>)</span>
        {
            <span class="hljs-keyword">return</span> a * b;
        }
    }
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>MathUtils</code> class is defined as <code>static</code>, meaning it cannot be instantiated.</p>
</li>
<li><p>It contains three static methods: <code>Add</code>, <code>Subtract</code>, and <code>Multiply</code>.</p>
</li>
<li><p>These methods can be called directly on the <code>MathUtils</code> class without creating an instance.</p>
</li>
</ul>
<p>Before you can use this, you need to call it in your <code>Program.cs</code>. When you create any C# application, the entry point is <code>Program.cs</code>. You’ll need to go there and make sure to call these classes so that you can execute them. This is what we will be doing for the rest of the section.</p>
<h3 id="heading-how-to-use-static-methods-in-programcs">How to Use Static Methods in <code>Program.cs</code></h3>
<p>Now you can use the static methods defined in the <code>MathUtils</code> class as follows:</p>
<pre><code class="lang-csharp">
 <span class="hljs-comment">// program.cs</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">StaticClasses</span>
{
    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
             <span class="hljs-comment">// Call static methods from the MathUtils class</span>
            <span class="hljs-keyword">int</span> sum = MathUtils.Add(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>);
            <span class="hljs-comment">// Call the static method Subtract from the MathUtils class</span>
            <span class="hljs-keyword">int</span> difference = MathUtils.Subtract(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>);

            <span class="hljs-comment">// Call the static method Multiply from the MathUtils class</span>
            <span class="hljs-keyword">int</span> product = MathUtils.Multiply(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>);

            <span class="hljs-comment">// Display the results of the sum method</span>
            Console.WriteLine(<span class="hljs-string">$"Sum: <span class="hljs-subst">{sum}</span>"</span>); <span class="hljs-comment">// Output: 8</span>
            <span class="hljs-comment">// Display the results of the difference method</span>
            Console.WriteLine(<span class="hljs-string">$"Difference: <span class="hljs-subst">{difference}</span>"</span>); <span class="hljs-comment">// Output: 2</span>
            <span class="hljs-comment">// Display the results of the product method</span>
            Console.WriteLine(<span class="hljs-string">$"Product: <span class="hljs-subst">{product}</span>"</span>);  <span class="hljs-comment">// Output: 15</span>
        }
    }
}
</code></pre>
<h3 id="heading-when-to-use-statice-classes-vs-methods">When to Use Statice Classes vs Methods</h3>
<p>To decide when to use static classes or methods in C#, consider the following guidelines:</p>
<ol>
<li><p><strong>Use Static Classes when:</strong></p>
<ul>
<li><p>You need a collection of utility or helper methods that do not require any instance data.</p>
</li>
<li><p>The methods and properties are stateless and can be accessed globally without creating an object.</p>
</li>
<li><p>You want to group related functions that are not tied to a specific object state.</p>
</li>
<li><p>You need to ensure that the class cannot be instantiated or inherited.</p>
</li>
</ul>
</li>
<li><p><strong>Use Static Methods when:</strong></p>
<ul>
<li><p>You have a class that is mostly instance-based, but you need a few methods that do not depend on instance data.</p>
</li>
<li><p>The method performs a task that is independent of any object state and can be executed without an instance.</p>
</li>
<li><p>You want to provide a utility function within a class that can be accessed without creating an object of that class.</p>
</li>
</ul>
</li>
</ol>
<p>By using static classes and methods appropriately, you can enhance code organization, improve performance by avoiding unnecessary object creation, and ensure that certain functionalities are easily accessible throughout your application.</p>
<h3 id="heading-key-points-to-remember-about-static-classes-in-c">Key Points to Remember About Static Classes in C</h3>
<ul>
<li><p><strong>Cannot be Instantiated</strong>: You cannot create objects from a static class.</p>
</li>
<li><p><strong>Only static members</strong>: Static classes can only have static members. They do not support instance methods or fields.</p>
</li>
<li><p><strong>Sealed by default</strong>: Static classes are automatically sealed, so they cannot be inherited.</p>
</li>
<li><p><strong>Utility and helper methods</strong>: Static classes are usually used to group related utility or helper methods that don't need an object state.</p>
</li>
</ul>
<p>Static classes help organize and access utility methods and properties clearly and simply, making them important for creating efficient and maintainable code.</p>
<h2 id="heading-sealed-classes-in-c-sharp">Sealed Classes in C Sharp</h2>
<p>Sealed classes are a special type of class in C# that cannot be inherited. You can use them to prevent other classes from deriving from them, which can be useful for creating immutable types or ensuring that a class's behavior remains unchanged.</p>
<p>By sealing a class, you ensure that it cannot be modified or extended, making it useful for scenarios where you want to provide a specific implementation without allowing further alterations.</p>
<h3 id="heading-example-of-a-sealed-class-in-c">Example of a Sealed Class in C</h3>
<p>Here's an example of a sealed class in C#:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">SealedClasses</span>
{

    <span class="hljs-comment">// Define an abstract class</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
    {
        <span class="hljs-comment">// Abstract method to calculate the area</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>;
    }

     <span class="hljs-comment">// Define a sealed class</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
    {

        <span class="hljs-comment">//  Properties</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; }

        <span class="hljs-comment">// Constructor</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Rectangle</span>(<span class="hljs-params"><span class="hljs-keyword">double</span> width, <span class="hljs-keyword">double</span> height</span>)</span>
        {
            Width = width;
            Height = height;
        }

       <span class="hljs-comment">// Implement the CalculateArea method</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> Width * Height;
        }
    }
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>Shape</code> class is an abstract base class with an abstract method <code>CalculateArea()</code>.</p>
</li>
<li><p>The <code>Rectangle</code> class inherits from <code>Shape</code> and provides an implementation for <code>CalculateArea()</code>.</p>
</li>
<li><p>The <code>Rectangle</code> class is sealed, which means it cannot be inherited from. This ensures that the class's implementation cannot be modified or extended.</p>
</li>
</ul>
<h3 id="heading-how-to-use-the-sealed-rectangle-class-in-the-programcs">How to Use the Sealed Rectangle Class in the Program.cs</h3>
<p>Here's how you can use the <code>Rectangle</code> class in a <code>Program.cs</code> file:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">SealedClasses</span>
{
    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
            Rectangle rectangle = <span class="hljs-keyword">new</span> Rectangle(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>);
            <span class="hljs-keyword">double</span> area = rectangle.CalculateArea();

            Console.WriteLine(<span class="hljs-string">$"Area of the rectangle: <span class="hljs-subst">{area}</span>"</span>); <span class="hljs-comment">// Output: Area of the rectangle: 15</span>
        }
    }
}
</code></pre>
<p>In this example, the <code>Rectangle</code> class is sealed to ensure that its behavior cannot be changed through inheritance. This guarantees that the <code>Rectangle</code> class's implementation of <code>CalculateArea()</code> stays the same, which helps maintain consistent behavior.</p>
<h3 id="heading-when-to-use-sealed-classes">When to Use Sealed Classes</h3>
<p>Sealed classes are particularly useful in the following contexts:</p>
<ol>
<li><p><strong>Framework development</strong>: When developing frameworks or libraries, you might use sealed classes to lock down certain classes that are not intended to be extended by users. This helps maintain control over the framework's behavior and ensures that users cannot introduce bugs or inconsistencies by extending these classes.</p>
</li>
<li><p><strong>Preventing inheritance</strong>: If a class is designed to be a specific implementation with no need for further customization or extension, sealing it prevents other developers from creating subclasses that might alter its intended functionality.</p>
</li>
<li><p><strong>Finalizing class design</strong>: When a class has reached a point where its design is considered complete and no further changes or extensions are anticipated, sealing it can signal to other developers that the class should be used as-is.</p>
</li>
<li><p><strong>Avoiding overriding</strong>: In scenarios where overriding methods could lead to incorrect behavior or security issues, sealing the class ensures that its methods cannot be overridden, preserving the original logic and functionality.</p>
</li>
</ol>
<h3 id="heading-key-points-to-remember-about-sealed-classes">Key Points to Remember About Sealed Classes</h3>
<ul>
<li><p><strong>No inheritance</strong>: Sealed classes cannot be inherited, ensuring their behavior stays the same.</p>
</li>
<li><p><strong>Prevent modification</strong>: They prevent further inheritance, avoiding accidental changes or extensions.</p>
</li>
<li><p><strong>Immutable and specific</strong>: Sealed classes are useful for creating immutable classes or when you need a specific, unchangeable implementation.</p>
</li>
</ul>
<h3 id="heading-sealed-classes-vs-static-classes">Sealed Classes vs. Static Classes</h3>
<p>You might wonder why we need sealed classes if static classes are already sealed. The key differences are:</p>
<ul>
<li><p><strong>Static Classes</strong> are sealed and cannot be instantiated. They are used for grouping static methods and properties.</p>
</li>
<li><p><strong>Sealed Classes</strong> can be instantiated but cannot be inherited. This allows for creating objects that are protected from further subclassing.</p>
</li>
</ul>
<p>Sealed classes offer flexibility in creating classes that can be used directly without the risk of modification through inheritance.</p>
<h2 id="heading-concrete-classes-in-c-sharp">Concrete Classes in C Sharp</h2>
<p>Concrete classes are essential in <code>object-oriented programming</code> in C#. They are fully implemented classes that you can use to create objects directly.</p>
<p>Unlike <code>abstract classes</code> or <code>interfaces</code>, concrete classes have complete implementations of all their methods and properties, making them versatile and fundamental to most C# applications.</p>
<p>A concrete class is not abstract. It includes full implementations of all its members—methods, properties, fields, and so on—and can be used to create objects. These classes represent real-world entities or concepts in your application, encapsulating both data (stored in fields or properties) and behavior (defined by methods).</p>
<h3 id="heading-example-defining-a-concrete-class-in-c">Example: Defining a Concrete Class in C</h3>
<p>Here's a simple example of a concrete class in C#:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Define a concrete class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Speak</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"The animal makes a sound."</span>);
    }
}

<span class="hljs-comment">// Define a derived class that inherits from the Animal class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> : <span class="hljs-title">Animal</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Bark</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"The dog barks."</span>);
    }
}
</code></pre>
<p>In this example, the <code>Animal</code> class is a concrete class with a method <code>Speak</code> that represents a generic sound made by any animal. The <code>Dog</code> class inherits from <code>Animal</code> and adds a <code>Bark</code> method to represent a sound specific to dogs. Both <code>Animal</code> and <code>Dog</code> are concrete classes because they can be instantiated and used to create objects.</p>
<h3 id="heading-how-to-instantiate-and-use-concrete-classes">How to Instantiate and Use Concrete Classes</h3>
<p>Here's how you can use the <code>Dog</code> class in a <code>Program.cs</code> file:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// program.cs</span>
<span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-comment">// Create an instance of the Dog class</span>
        Dog myDog = <span class="hljs-keyword">new</span> Dog();

        <span class="hljs-comment">// Call the inherited method</span>
        myDog.Speak(); <span class="hljs-comment">// Output: The animal makes a sound.</span>

        <span class="hljs-comment">// Call the method defined in the Dog class</span>
        myDog.Bark();  <span class="hljs-comment">// Output: The dog barks.</span>
    }
}
</code></pre>
<p>In this example, we create an instance of the <code>Dog</code> class called <code>myDog</code>. We first call the <code>Speak</code> method, which is inherited from the <code>Animal</code> class, and then the <code>Bark</code> method from the <code>Dog</code> class. This shows how concrete classes can include both inherited and unique behaviors.</p>
<h3 id="heading-real-world-example-concrete-class-for-a-product">Real-World Example: Concrete Class for a Product</h3>
<p>To illustrate the practical application of concrete classes, consider the following example of a <code>Product</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define a concrete class for a product</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>
{
    <span class="hljs-comment">// Data properties</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> Price { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-comment">// Method to display product information</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisplayInfo</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"Product: <span class="hljs-subst">{Name}</span>, Price: <span class="hljs-subst">{Price:C}</span>"</span>);
    }
}
</code></pre>
<p>This <code>Product</code> class is a concrete class with properties <code>Name</code> and <code>Price</code> to store information about a product. The <code>DisplayInfo</code> method provides a way to display the product’s details.</p>
<h4 id="heading-how-to-use-the-product-class">How to Use the <code>Product</code> Class</h4>
<p>Here's how you can use the <code>Product</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-comment">// Create an instance of the Product class</span>
        Product product = <span class="hljs-keyword">new</span> Product
        {
            Name = <span class="hljs-string">"Laptop"</span>,
            Price = <span class="hljs-number">1299.99</span>m
        };

        <span class="hljs-comment">// Display product information</span>
        product.DisplayInfo(); <span class="hljs-comment">// Output: Product: Laptop, Price: $1,299.99</span>
    }
}
</code></pre>
<p>In this scenario, the <code>Product</code> class is used to create a <code>product</code> object. The <code>DisplayInfo</code> method is called to show the product's name and price. This demonstrates how concrete classes are used to model and work with real-world data.</p>
<h3 id="heading-key-points-to-remember-about-concrete-classes">Key Points to Remember About Concrete Classes</h3>
<ul>
<li><p><strong>Instantiable</strong>: Concrete classes can be instantiated, allowing you to create objects that represent specific entities or concepts in your application.</p>
</li>
<li><p><strong>Complete implementation</strong>: Concrete classes provide full implementations of all methods and properties, unlike abstract classes or interfaces.</p>
</li>
<li><p><strong>Common use</strong>: They are the most common type of class in C#, used to define objects with specific behavior and data.</p>
</li>
</ul>
<p>Concrete classes are essential for C# development, enabling you to define and work with objects that model real-world entities within your applications. Understanding how to effectively use concrete classes is crucial for building robust, object-oriented software.</p>
<h2 id="heading-abstract-classes-in-c-sharp">Abstract Classes in C Sharp</h2>
<p>In C#, abstract classes are a powerful feature that allow you to define a blueprint for other classes without providing complete implementations. They serve as base classes that cannot be instantiated directly but can be inherited by other classes that will provide specific implementations for the abstract methods defined within them. This design helps enforce consistency across related classes while allowing flexibility in how certain behaviors are implemented.</p>
<h3 id="heading-what-does-instantiated-mean">What Does "Instantiated" Mean?</h3>
<p>Before exploring abstract classes, let's clarify what it means to instantiate a class. Instantiation is the process of creating an object from a class. When you use the <code>new</code> keyword in C#, you are creating an instance (or object) of that class.</p>
<p>But abstract classes cannot be instantiated directly. They must be inherited by a non-abstract (concrete) class that provides implementations for the abstract methods.</p>
<h3 id="heading-understanding-abstract-classes-and-abstract-methods">Understanding Abstract Classes and Abstract Methods</h3>
<p><strong>Abstract classes</strong> are classes you can't create objects from directly. They act as templates for other classes. They can have both complete methods and methods without a body (abstract methods). Abstract classes help set up a common interface and shared behavior for related classes.</p>
<p><strong>Abstract methods</strong>, on the other hand, are methods in an abstract class that don't have a body. Any non-abstract class that inherits from the abstract class must provide a body for these methods. This ensures all subclasses have a consistent interface.</p>
<h3 id="heading-real-world-example-bank-account-management">Real-World Example: Bank Account Management</h3>
<p>Let's explore a real-world example to illustrate the concept of abstract classes and abstract methods in C#.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;

<span class="hljs-comment">// define an abstract class</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">AbstractClasses</span>
{
    <span class="hljs-comment">// Abstract class</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BankAccount</span>
    {
        <span class="hljs-comment">// Properties</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AccountNumber { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> Balance { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">protected</span> <span class="hljs-keyword">set</span>; }

        <span class="hljs-comment">// Constructor</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BankAccount</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> accountNumber, <span class="hljs-keyword">decimal</span> initialBalance</span>)</span>
        {
            AccountNumber = accountNumber;
            Balance = initialBalance;
        }

        <span class="hljs-comment">// Abstract methods</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Deposit</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>;
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>;
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisplayAccountInfo</span>(<span class="hljs-params"></span>)</span>;
    }

    <span class="hljs-comment">// Derived class: SavingsAccount</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SavingsAccount</span> : <span class="hljs-title">BankAccount</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">decimal</span> interestRate;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SavingsAccount</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> accountNumber, <span class="hljs-keyword">decimal</span> initialBalance, <span class="hljs-keyword">decimal</span> interestRate</span>)
            : <span class="hljs-title">base</span>(<span class="hljs-params">accountNumber, initialBalance</span>)</span>
        {
            <span class="hljs-keyword">this</span>.interestRate = interestRate;
        }

        <span class="hljs-comment">// Implementing abstract methods</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Deposit</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
        {
            Balance += amount;
            Console.WriteLine(<span class="hljs-string">$"Deposited <span class="hljs-subst">{amount}</span> to Savings Account <span class="hljs-subst">{AccountNumber}</span>. New Balance: <span class="hljs-subst">{Balance}</span>"</span>);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
        {
            <span class="hljs-keyword">if</span> (amount &gt; Balance)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Insufficient funds."</span>);
            }
            Balance -= amount;
            Console.WriteLine(<span class="hljs-string">$"Withdrew <span class="hljs-subst">{amount}</span> from Savings Account <span class="hljs-subst">{AccountNumber}</span>. New Balance: <span class="hljs-subst">{Balance}</span>"</span>);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisplayAccountInfo</span>(<span class="hljs-params"></span>)</span>
        {
            Console.WriteLine(<span class="hljs-string">$"Savings Account <span class="hljs-subst">{AccountNumber}</span> - Balance: <span class="hljs-subst">{Balance}</span>, Interest Rate: <span class="hljs-subst">{interestRate}</span>%"</span>);
        }
    }

    <span class="hljs-comment">// Derived class: CheckingAccount</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CheckingAccount</span> : <span class="hljs-title">BankAccount</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">decimal</span> overdraftLimit;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CheckingAccount</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> accountNumber, <span class="hljs-keyword">decimal</span> initialBalance, <span class="hljs-keyword">decimal</span> overdraftLimit</span>)
            : <span class="hljs-title">base</span>(<span class="hljs-params">accountNumber, initialBalance</span>)</span>
        {
            <span class="hljs-keyword">this</span>.overdraftLimit = overdraftLimit;
        }

        <span class="hljs-comment">// Implementing abstract methods</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Deposit</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
        {
            Balance += amount;
            Console.WriteLine(<span class="hljs-string">$"Deposited <span class="hljs-subst">{amount}</span> to Checking Account <span class="hljs-subst">{AccountNumber}</span>. New Balance: <span class="hljs-subst">{Balance}</span>"</span>);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">decimal</span> amount</span>)</span>
        {
            <span class="hljs-keyword">if</span> (amount &gt; Balance + overdraftLimit)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Overdraft limit exceeded."</span>);
            }
            Balance -= amount;
            Console.WriteLine(<span class="hljs-string">$"Withdrew <span class="hljs-subst">{amount}</span> from Checking Account <span class="hljs-subst">{AccountNumber}</span>. New Balance: <span class="hljs-subst">{Balance}</span>"</span>);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisplayAccountInfo</span>(<span class="hljs-params"></span>)</span>
        {
            Console.WriteLine(<span class="hljs-string">$"Checking Account <span class="hljs-subst">{AccountNumber}</span> - Balance: <span class="hljs-subst">{Balance}</span>, Overdraft Limit: <span class="hljs-subst">{overdraftLimit}</span>"</span>);
        }
    }
}
</code></pre>
<p>In this example, the <code>BankAccount</code> class is an abstract class that defines a common interface for different types of bank accounts. It includes abstract methods like <code>Deposit</code>, <code>Withdraw</code>, and <code>DisplayAccountInfo</code>, which must be implemented by any class that inherits from <code>BankAccount</code>.</p>
<p>The <code>SavingsAccount</code> and <code>CheckingAccount</code> classes inherit from <code>BankAccount</code> and provide specific implementations for these abstract methods. This design enforces that every type of bank account must implement deposit, withdrawal, and display functions, while still allowing each account type to implement these functions in a way that makes sense for that specific type.</p>
<h3 id="heading-how-to-use-abstract-classes-in-a-program">How to Use Abstract Classes in a Program</h3>
<p>Let's see how we can use the <code>SavingsAccount</code> and <code>CheckingAccount</code> classes in a <code>Program.cs</code> file.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">AbstractClasses</span>
{
    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
            <span class="hljs-comment">// Create a savings account</span>
            BankAccount savings = <span class="hljs-keyword">new</span> SavingsAccount(<span class="hljs-string">"SA123"</span>, <span class="hljs-number">1000</span>, <span class="hljs-number">1.5</span>m);
            <span class="hljs-comment">// Create a checking account</span>
            BankAccount checking = <span class="hljs-keyword">new</span> CheckingAccount(<span class="hljs-string">"CA123"</span>, <span class="hljs-number">500</span>, <span class="hljs-number">200</span>);

            <span class="hljs-comment">// Deposit and withdraw from the savings account</span>
            savings.DisplayAccountInfo();

           <span class="hljs-comment">// Deposit and withdraw from the checking account</span>
            savings.Deposit(<span class="hljs-number">200</span>);

            savings.Withdraw(<span class="hljs-number">100</span>);
            <span class="hljs-comment">// Display the updated account information</span>
            savings.DisplayAccountInfo();

            checking.DisplayAccountInfo();

             <span class="hljs-comment">// Deposit and withdraw from the checking account</span>
            checking.Deposit(<span class="hljs-number">300</span>);

            checking.Withdraw(<span class="hljs-number">600</span>);

            <span class="hljs-comment">// Display the updated account information</span>
            checking.DisplayAccountInfo();

            <span class="hljs-keyword">try</span>
            {
                checking.Withdraw(<span class="hljs-number">200</span>);
            }
            <span class="hljs-keyword">catch</span> (InvalidOperationException ex)
            {
                Console.WriteLine(<span class="hljs-string">$"Error: <span class="hljs-subst">{ex.Message}</span>"</span>);
            }

            checking.DisplayAccountInfo();
        }
    }
}
</code></pre>
<p>This program will produce the following output:</p>
<pre><code class="lang-markdown">Savings Account SA123 - Balance: 1000, Interest Rate: 1.5%
Deposited 200 to Savings Account SA123. New Balance: 1200
Withdrew 100 from Savings Account SA123. New Balance: 1100
Savings Account SA123 - Balance: 1100, Interest Rate: 1.5%
Checking Account CA123 - Balance: 500, Overdraft Limit: 200
Deposited 300 to Checking Account CA123. New Balance: 800
Withdrew 600 from Checking Account CA123. New Balance: 200
Checking Account CA123 - Balance: 200, Overdraft Limit: 200
Withdrew 200 from Checking Account CA123. New Balance: 0
Checking Account CA123 - Balance: 0, Overdraft Limit: 200
</code></pre>
<p>In this example, the <code>SavingsAccount</code> and <code>CheckingAccount</code> objects are created, and the abstract methods <code>Deposit</code>, <code>Withdraw</code>, and <code>DisplayAccountInfo</code> are called. The abstract class <code>BankAccount</code> ensures that both account types have these methods, while the derived classes provide the specific functionality.</p>
<h3 id="heading-key-points-to-remember-about-abstract-classes">Key Points to Remember About Abstract Classes</h3>
<ul>
<li><p><strong>Cannot be instantiated</strong>: You can't create an instance of an abstract class directly. A subclass must inherit it and provide the implementations for the abstract methods.</p>
</li>
<li><p><strong>Contain abstract methods</strong>: Abstract methods in an abstract class have no body. Any non-abstract class that inherits from the abstract class must implement these methods.</p>
</li>
<li><p><strong>Define common interfaces</strong>: Abstract classes set a common interface for related classes, ensuring they are consistent while allowing different implementations.</p>
</li>
</ul>
<p>Abstract classes are important in C#. They help enforce a structure across related classes but still allow for specific details. By using abstract classes, you can make your code more organized, easier to maintain, and extend.</p>
<h2 id="heading-singleton-classes-in-c-sharp">Singleton Classes in C Sharp</h2>
<p>Singleton classes are a design pattern that restricts the instantiation of a class to one single instance. This is particularly useful when you need a single, shared resource across your application, such as a configuration manager, logging service, or database connection.</p>
<h3 id="heading-why-use-singleton-classes-in-c">Why Use Singleton Classes in C#?</h3>
<p>Imagine you have a class responsible for managing a database connection. You don’t want multiple instances of this class running around, potentially causing issues with resource management or inconsistent data. A Singleton class ensures that only one instance is created and provides a global point of access to it.</p>
<h3 id="heading-example-defining-a-singleton-class">Example: Defining a Singleton Class</h3>
<p>Let’s now see how you can implement a Singleton class in C#:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define a singleton class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Singleton</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Singleton instance;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">object</span> lockObject = <span class="hljs-keyword">new</span> <span class="hljs-keyword">object</span>();

    <span class="hljs-comment">// Private constructor prevents instantiation from outside the class</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">Singleton</span>(<span class="hljs-params"></span>)</span>
    {
    }

    <span class="hljs-comment">// Public property to access the single instance of the class</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Singleton Instance
    {
        <span class="hljs-keyword">get</span>
        {
            <span class="hljs-comment">// Ensure thread safety</span>
            <span class="hljs-keyword">lock</span> (lockObject)
            {
                <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">null</span>)
                {
                    instance = <span class="hljs-keyword">new</span> Singleton();
                }
            }
            <span class="hljs-keyword">return</span> instance;
        }
    }

    <span class="hljs-comment">// Example method to demonstrate the singleton instance</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">PrintMessage</span>(<span class="hljs-params"></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">"Hello, I am a singleton class."</span>);
    }
}
</code></pre>
<p>In this example, the <code>Singleton</code> class is defined with a private constructor, which prevents other classes from creating new instances. The static property <code>Instance</code> returns the single instance of the class, creating it if it doesn't already exist. The <code>lockObject</code> ensures that the class is thread-safe, meaning that even in a multi-threaded environment, only one instance will be created.</p>
<p>The <code>PrintMessage</code> method is just a simple example to show that the Singleton instance can be used like any other class instance.</p>
<h3 id="heading-how-to-use-the-singleton-class-in-programcs">How to Use the Singleton Class in <code>Program.cs</code></h3>
<p>Now let’s see how you can use this Singleton class in your application:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-comment">// Retrieve the single instance of the Singleton class</span>
        Singleton singleton1 = Singleton.Instance;
        singleton1.PrintMessage(); <span class="hljs-comment">// Output: Hello, I am a singleton class.</span>

        <span class="hljs-comment">// Retrieve the instance again</span>
        Singleton singleton2 = Singleton.Instance;

        <span class="hljs-comment">// Check if both instances are the same</span>
        Console.WriteLine(singleton1 == singleton2); <span class="hljs-comment">// Output: True</span>
    }
}
</code></pre>
<p>In this example, we retrieve the Singleton instance twice. Because the class is a Singleton, both <code>singleton1</code> and <code>singleton2</code> refer to the same instance. The <code>==</code> operator confirms this by returning <code>true</code>.</p>
<h3 id="heading-how-to-extend-the-singleton-example">How to Extend the Singleton Example</h3>
<p>You can expand the Singleton pattern to handle more complex scenarios. For example, you could initialize the Singleton instance with configuration data:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ConfigurationManager</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> ConfigurationManager instance;
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-title">Dictionary</span>&lt;<span class="hljs-title">string</span>, <span class="hljs-title">string</span>&gt; settings</span> = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt;();

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">ConfigurationManager</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Simulate loading settings from a configuration file</span>
        settings[<span class="hljs-string">"AppName"</span>] = <span class="hljs-string">"MyApplication"</span>;
        settings[<span class="hljs-string">"Version"</span>] = <span class="hljs-string">"1.0.0"</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfigurationManager Instance
    {
        <span class="hljs-keyword">get</span>
        {
            <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">null</span>)
            {
                instance = <span class="hljs-keyword">new</span> ConfigurationManager();
            }
            <span class="hljs-keyword">return</span> instance;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetSetting</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> key</span>)</span>
    {
        <span class="hljs-keyword">return</span> settings.ContainsKey(key) ? settings[key] : <span class="hljs-literal">null</span>;
    }
}
</code></pre>
<p>Here, <code>ConfigurationManager</code> is a Singleton class that loads and manages application settings. The <code>GetSetting</code> method allows you to retrieve specific configuration values, ensuring that all parts of your application use the same settings.</p>
<h3 id="heading-key-points-to-remember-about-singleton-classes">Key Points to Remember About Singleton Classes</h3>
<ul>
<li><p><strong>Single instance</strong>: Singleton classes ensure that only one instance of the class exists in the application.</p>
</li>
<li><p><strong>Global access</strong>: Singleton provides a global point of access to the instance, making it easy to use across different parts of your application.</p>
</li>
<li><p><strong>Thread safety</strong>: In multi-threaded environments, ensure your Singleton is thread-safe to avoid creating multiple instances.</p>
</li>
<li><p><strong>Use cases</strong>: Common use cases for Singleton include managing configurations, logging services, and database connections.</p>
</li>
</ul>
<p>Singleton classes are a fundamental design pattern in software engineering, offering a simple yet powerful way to manage shared resources. Understanding and correctly implementing Singletons can help you write more efficient and maintainable code.</p>
<h2 id="heading-generic-classes-in-c-sharp">Generic Classes in C Sharp</h2>
<p>Generic classes in C# provide a powerful way to create reusable and type-safe code. By using generic classes, you can design a single class that works with any data type, eliminating the need for type-specific implementations. This makes your code more flexible and reduces redundancy.</p>
<h3 id="heading-why-use-generic-classes">Why Use Generic Classes?</h3>
<p>Imagine you need to implement a stack that stores integers. Later, you might need another stack to store strings.</p>
<p>Instead of writing two separate classes, you can write one generic stack class that can handle both data types—and any others you might need. Generic classes help you avoid code duplication and make your codebase easier to maintain.</p>
<h3 id="heading-example-defining-a-generic-class">Example: Defining a Generic Class</h3>
<p>Let’s take a look at a simple implementation of a generic stack class:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define a generic class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Stack</span>&lt;<span class="hljs-title">T</span>&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">T</span>&gt; items</span> = <span class="hljs-keyword">new</span> List&lt;T&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Push</span>(<span class="hljs-params">T item</span>)</span>
    {
        items.Add(item);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> T <span class="hljs-title">Pop</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">if</span> (items.Count == <span class="hljs-number">0</span>)
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"The stack is empty."</span>);
        }
        T item = items[items.Count - <span class="hljs-number">1</span>];
        items.RemoveAt(items.Count - <span class="hljs-number">1</span>);
        <span class="hljs-keyword">return</span> item;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> T <span class="hljs-title">Peek</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">if</span> (items.Count == <span class="hljs-number">0</span>)
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"The stack is empty."</span>);
        }
        <span class="hljs-keyword">return</span> items[items.Count - <span class="hljs-number">1</span>];
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">IsEmpty</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">return</span> items.Count == <span class="hljs-number">0</span>;
    }
}
</code></pre>
<p>In this example, the <code>Stack&lt;T&gt;</code> class is defined with a type parameter <code>T</code>. This type parameter is a placeholder that represents the type of data the stack will store. The class includes methods like <code>Push</code> to add an item to the stack, <code>Pop</code> to remove and return the top item, <code>Peek</code> to view the top item without removing it, and <code>IsEmpty</code> to check if the stack is empty.</p>
<p>Because <code>Stack&lt;T&gt;</code> is generic, you can use it with any data type, whether it's <code>int</code>, <code>string</code>, or even a custom class.</p>
<h3 id="heading-how-to-use-the-stack-class-in-programcs">How to Use the Stack Class in <code>Program.cs</code></h3>
<p>Let’s see how this generic <code>Stack</code> class can be used in a program:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-comment">// Stack for integers</span>
        Stack&lt;<span class="hljs-keyword">int</span>&gt; intStack = <span class="hljs-keyword">new</span> Stack&lt;<span class="hljs-keyword">int</span>&gt;();
        intStack.Push(<span class="hljs-number">10</span>);
        intStack.Push(<span class="hljs-number">20</span>);
        Console.WriteLine(intStack.Pop()); <span class="hljs-comment">// Output: 20</span>
        Console.WriteLine(intStack.Peek()); <span class="hljs-comment">// Output: 10</span>

        <span class="hljs-comment">// Stack for strings</span>
        Stack&lt;<span class="hljs-keyword">string</span>&gt; stringStack = <span class="hljs-keyword">new</span> Stack&lt;<span class="hljs-keyword">string</span>&gt;();
        stringStack.Push(<span class="hljs-string">"Hello"</span>);
        stringStack.Push(<span class="hljs-string">"World"</span>);
        Console.WriteLine(stringStack.Pop()); <span class="hljs-comment">// Output: World</span>
        Console.WriteLine(stringStack.Peek()); <span class="hljs-comment">// Output: Hello</span>
    }
}
</code></pre>
<p>In this example, we create two instances of the <code>Stack</code> class: one that stores integers and another that stores strings. The flexibility of generics allows us to use the same class to work with different data types, making our code more reusable and concise.</p>
<h3 id="heading-how-to-extend-the-generic-class">How to Extend the Generic Class</h3>
<p>Let’s take it a step further and extend our <code>Stack</code> class to include a method that returns all items as an array:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> T[] <span class="hljs-title">ToArray</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">return</span> items.ToArray();
}
</code></pre>
<p>Now, you can easily convert the stack’s items into an array:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">int</span>[] intArray = intStack.ToArray();
<span class="hljs-keyword">string</span>[] stringArray = stringStack.ToArray();
</code></pre>
<p>This extension further showcases the power of generics, allowing the same method to work with different data types seamlessly.</p>
<h3 id="heading-key-points-to-remember-about-generic-classes">Key Points to Remember About Generic Classes</h3>
<ul>
<li><p><strong>Flexibility</strong>: Generic classes can handle any data type, making them adaptable and reusable.</p>
</li>
<li><p><strong>Type safety</strong>: Using type parameters ensures that your code is type-safe, catching errors during compile-time instead of runtime.</p>
</li>
<li><p><strong>Code reuse</strong>: Generics remove the need to duplicate code for different data types, resulting in cleaner and easier-to-maintain code.</p>
</li>
<li><p><strong>Type parameters</strong>: Generic classes use type parameters as placeholders for the actual data types you will use when creating an instance of the class.</p>
</li>
</ul>
<p>Generic classes are crucial in C# for building flexible, reusable, and type-safe code. By learning and using generics, you can create more reliable and maintainable applications.</p>
<h2 id="heading-internal-classes-in-c-sharp">Internal Classes in C Sharp</h2>
<p>Internal classes in C# are a powerful way to encapsulate implementation details within an assembly. By using the <code>internal</code> access modifier, you can restrict access to certain classes, ensuring they are only accessible within the same assembly.</p>
<p>This is particularly useful for hiding complex logic or utility classes that are not intended to be exposed to the public API of your library or application.</p>
<h3 id="heading-why-use-internal-classes">Why Use Internal Classes?</h3>
<p>In a large application, you may have classes that should only be used internally by your code and not by external consumers. For example, helper classes, utility functions, or components of a larger system that do not need to be exposed outside the assembly can be marked as <code>internal</code>. This ensures that your public API remains clean and focused while still allowing full functionality within the assembly.</p>
<h3 id="heading-example-defining-an-internal-class">Example: Defining an Internal Class</h3>
<p>Let’s consider a scenario where you have a library that processes orders. You might have a class that handles the complex logic of calculating discounts, but you don't want this class to be accessible to users of your library. Instead, you only expose the main <code>OrderProcessor</code> class, keeping the discount logic hidden with an internal class.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define a public class that uses an internal class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">OrderProcessor</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessOrder</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> orderId</span>)</span>
    {
        <span class="hljs-comment">// Internal class is used here</span>
        DiscountCalculator calculator = <span class="hljs-keyword">new</span> DiscountCalculator();
        <span class="hljs-keyword">decimal</span> discount = calculator.CalculateDiscount(orderId);
        Console.WriteLine(<span class="hljs-string">$"Order <span class="hljs-subst">{orderId}</span> processed with a discount of <span class="hljs-subst">{discount:C}</span>"</span>);
    }

    <span class="hljs-comment">// Internal class that handles discount calculations</span>
    <span class="hljs-keyword">internal</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DiscountCalculator</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> <span class="hljs-title">CalculateDiscount</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> orderId</span>)</span>
        {
            <span class="hljs-comment">// Complex discount calculation logic</span>
            <span class="hljs-keyword">return</span> orderId * <span class="hljs-number">0.05</span>m;
        }
    }
}
</code></pre>
<p>In this example, the <code>DiscountCalculator</code> class is marked as <code>internal</code>, meaning it’s only accessible within the assembly. The <code>OrderProcessor</code> class, which is <code>public</code>, uses this internal class to process orders. External users of the library can call <code>ProcessOrder</code> without needing to know about or interact with the <code>DiscountCalculator</code> class.</p>
<h3 id="heading-how-to-use-the-internal-class-in-programcs">How to Use the Internal Class in <code>Program.cs</code></h3>
<p>Now, let's see how this works in practice:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        OrderProcessor processor = <span class="hljs-keyword">new</span> OrderProcessor();
        processor.ProcessOrder(<span class="hljs-number">12345</span>); <span class="hljs-comment">// Output: Order 12345 processed with a discount of $617.25</span>
    }
}
</code></pre>
<p>In this example, the <code>ProcessOrder</code> method is publicly accessible, but the internal workings of discount calculation remain hidden, providing a clean and secure API.</p>
<h3 id="heading-key-points-to-remember-about-internal-classes">Key Points to Remember About Internal Classes</h3>
<ul>
<li><p><strong>Limited access</strong>: Internal classes can only be accessed within the same assembly, which helps keep your public API simple and focused.</p>
</li>
<li><p><strong>Encapsulation</strong>: They are used to hide implementation details, like helper functions or complex logic, that shouldn't be publicly visible.</p>
</li>
<li><p><strong>Visibility control</strong>: The <code>internal</code> access modifier lets you control which classes and members are visible, ensuring only the necessary parts of your code are accessible to other assemblies.</p>
</li>
</ul>
<p>Internal classes are important for managing complex applications, allowing you to control what parts of your code can be accessed from outside your assembly. By hiding details and limiting access, you can keep your codebase clean, easy to maintain, and secure.</p>
<h2 id="heading-nested-classes-in-c-sharp">Nested Classes in C Sharp</h2>
<p>Nested classes in C# are defined within another class. This structure is useful for grouping related classes together and encapsulating the implementation details. Nested classes can be either static or non-static, and they have direct access to the private members of their enclosing class.</p>
<h3 id="heading-why-use-nested-classes">Why Use Nested Classes?</h3>
<p>Nested classes are particularly useful when a class is closely tied to the logic of another class and isn’t meant to be used independently. They allow you to encapsulate helper classes, hide them from other parts of the program, and keep related code together. This can lead to a cleaner, more organized codebase.</p>
<h3 id="heading-example-defining-a-nested-class">Example: Defining a Nested Class</h3>
<p>Let’s consider a scenario where we have a class that represents a <code>Car</code> and another class that represents a <code>Engine</code>. Since the <code>Engine</code> class is closely related to the <code>Car</code> class and doesn’t make much sense on its own, we can define it as a nested class within <code>Car</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define a class with a nested class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>
{
    <span class="hljs-comment">// Define private fields</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> model;
    <span class="hljs-keyword">private</span> Engine carEngine;

   <span class="hljs-comment">// Constructor</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> model</span>)</span>
    {
        <span class="hljs-keyword">this</span>.model = model;
        carEngine = <span class="hljs-keyword">new</span> Engine();
    }


    <span class="hljs-comment">// Method to start the car</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
    {
        carEngine.StartEngine();
        Console.WriteLine(<span class="hljs-string">$"<span class="hljs-subst">{model}</span> is starting..."</span>);
    }

    <span class="hljs-comment">// Nested class</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartEngine</span>(<span class="hljs-params"></span>)</span>
        {
            Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
        }
    }
}
</code></pre>
<p>In this example, the <code>Car</code> class has a private field <code>model</code> and a method <code>StartCar</code> that starts the car. The <code>Engine</code> class is nested within the <code>Car</code> class and contains a <code>StartEngine</code> method. By nesting <code>Engine</code> inside <code>Car</code>, we express the close relationship between the two.</p>
<h3 id="heading-how-to-use-the-nested-class-in-programcs">How to Use the Nested Class in <code>Program.cs</code></h3>
<p>Let’s see how we can use the <code>Car</code> class and its nested <code>Engine</code> class in a program:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        Car myCar = <span class="hljs-keyword">new</span> Car(<span class="hljs-string">"Toyota"</span>);
        myCar.StartCar(); <span class="hljs-comment">// Output: Engine started. Toyota is starting...</span>

        <span class="hljs-comment">// Although you can create an instance of the nested class separately, it usually makes sense to use it through the outer class</span>
        Car.Engine engine = <span class="hljs-keyword">new</span> Car.Engine();
        engine.StartEngine(); <span class="hljs-comment">// Output: Engine started.</span>
    }
}
</code></pre>
<p>In this example, we create an instance of the <code>Car</code> class and call the <code>StartCar</code> method, which internally calls the <code>StartEngine</code> method of the nested <code>Engine</code> class. While it's possible to instantiate the nested class separately, it’s more common to access it through the outer class, emphasizing the relationship between the two.</p>
<h3 id="heading-key-points-to-remember-about-nested-classes">Key Points to Remember About Nested Classes</h3>
<ul>
<li><p><strong>Encapsulation</strong>: Nested classes keep details hidden that shouldn't be seen outside the main class.</p>
</li>
<li><p><strong>Access to private members</strong>: Nested classes can access private parts of the main class, making them good for helper classes that need to work with the main class's internal parts.</p>
</li>
<li><p><strong>Organization</strong>: Use nested classes to keep related classes together, which makes the code cleaner and more organized.</p>
</li>
<li><p><strong>Static or non-static</strong>: Nested classes can be static or non-static. Static nested classes can't access the instance parts of the main class directly, but non-static nested classes can.</p>
</li>
</ul>
<p>Nested classes are a useful way to organize your code, especially for complex objects with closely related parts. Keeping related classes together makes your code easier to manage and maintain.</p>
<h2 id="heading-partial-classes-in-c-sharp">Partial Classes in C Sharp</h2>
<p>Partial classes in C# allow you to split a class definition across multiple files. This feature is particularly useful in large projects, where it can be beneficial to break a complex class into smaller, more manageable sections.</p>
<p>By using the <code>partial</code> keyword, you can organize your code better, especially when working with generated code or collaborating in a team environment.</p>
<h3 id="heading-why-use-partial-classes">Why Use Partial Classes?</h3>
<p>Imagine you’re working on a large application where a single class contains hundreds of lines of code. This can become difficult to manage and maintain. By using partial classes, you can divide the class into logical parts, each residing in a separate file. This not only makes the code more readable but also allows multiple developers to work on different parts of the class simultaneously without causing merge conflicts.</p>
<h3 id="heading-example-defining-a-partial-class-in-c">Example: Defining a Partial Class in C</h3>
<p>Let’s say we have a class that handles various operations for an employee management system. Instead of putting all methods in one file, we can split them across multiple files using partial classes.</p>
<p><strong>File 1:</strong> <code>PartialClass_Methods1.cs</code></p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define a partial class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">partial</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmployeeOperations</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddEmployee</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"Employee <span class="hljs-subst">{name}</span> added."</span>);
    }
}
</code></pre>
<p><strong>File 2:</strong> <code>PartialClass_Methods2.cs</code></p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define the other part of the partial class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">partial</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmployeeOperations</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RemoveEmployee</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"Employee <span class="hljs-subst">{name}</span> removed."</span>);
    }
}
</code></pre>
<p>In these examples, the <code>EmployeeOperations</code> class is split into two files, each containing a part of the class. The first file handles adding employees, while the second file handles removing them.</p>
<h3 id="heading-how-to-use-the-partial-class-in-programcs">How to Use the Partial Class in <code>Program.cs</code></h3>
<p>Now, let’s use the <code>EmployeeOperations</code> class in our <code>Program.cs</code> file:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        EmployeeOperations operations = <span class="hljs-keyword">new</span> EmployeeOperations();

        operations.AddEmployee(<span class="hljs-string">"John Doe"</span>);    <span class="hljs-comment">// Output: Employee John Doe added.</span>
        operations.RemoveEmployee(<span class="hljs-string">"John Doe"</span>); <span class="hljs-comment">// Output: Employee John Doe removed.</span>
    }
}
</code></pre>
<p>In this example, the <code>EmployeeOperations</code> class, although defined in multiple files, behaves like a single class. The methods <code>AddEmployee</code> and <code>RemoveEmployee</code> are seamlessly combined, providing a clean and organized way to manage operations.</p>
<h3 id="heading-key-points-to-remember-about-partial-classes">Key Points to Remember About Partial Classes</h3>
<ul>
<li><p><strong>Code organization</strong>: Partial classes help keep large classes organized by splitting them into smaller, focused sections.</p>
</li>
<li><p><strong>Team collaboration</strong>: Multiple developers can work on different parts of the same class without interfering with each other’s code.</p>
</li>
<li><p><strong>Generated code</strong>: Often used with auto-generated code, where part of the class is generated by a tool, and the rest is written manually.</p>
</li>
</ul>
<p>Partial classes are a powerful feature in C# that allows for better code management, especially in large-scale applications. By breaking down a class into logical components, you can maintain clean, readable, and maintainable code.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Classes are the building blocks of object-oriented programming in C#. By understanding the different types of classes—abstract, static, sealed, concrete, and singleton—you can create well-structured, maintainable, and efficient code.</p>
<p>Whether you’re designing utility classes, defining abstract interfaces, or encapsulating complex logic, classes play a crucial role in shaping your application’s architecture.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Benchmark Your Code in C# ]]>
                </title>
                <description>
                    <![CDATA[ Knowing how your code performs is a crucial part of development. We strive to write the most optimal and performant code whilst keeping readability. In this article, I will show you how to test the performance of your code, benchmark your code, and i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-benchmark-your-code-in-csharp/</link>
                <guid isPermaLink="false">673bdcd6088133abf555d52f</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ .NET ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Tue, 19 Nov 2024 00:33:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731752379027/4ec760c3-4183-4852-9d3d-e3a5c75b4bcf.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Knowing how your code performs is a crucial part of development. We strive to write the most optimal and performant code whilst keeping readability.</p>
<p>In this article, I will show you how to test the performance of your code, benchmark your code, and identify areas of improvement within your code base.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-benchmarking">What is Benchmarking?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-using-a-stopwatch-is-not-reliable">Why Using a Stopwatch is Not Reliable</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-benchmarkdotnet">How to Use BenchMarkDotnet</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-else-can-you-test-with-benchmarkdotnet">What Else Can You Test with BenchmarkDotnet?</a></p>
</li>
</ul>
<h2 id="heading-what-is-benchmarking">What is Benchmarking?</h2>
<p>Benchmarking measures the performance of your code, application, system, or hardware under specific conditions.  </p>
<p>The goal is to gather precise data about how the system behaves for metrics like processing speed, memory usage, resource consumption, or throughput and to identify areas where performance can be optimized.</p>
<h2 id="heading-why-using-a-stopwatch-is-not-reliable">Why Using a Stopwatch is Not Reliable</h2>
<p>Using the <code>Stopwatch</code> class for benchmarking in C# comes with many problems. Although it provides a simple way to measure elapsed time on a method or process, it lacks the precision, control, and consistency needed for accurate benchmarking.  </p>
<p>Before I get into the negatives of this utility, let’s look at how you could use it for very simple tasks.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Diagnostics;

<span class="hljs-comment">// Create a new Stopwatch instance</span>
<span class="hljs-keyword">var</span> sw = <span class="hljs-keyword">new</span> Stopwatch();

<span class="hljs-comment">// Start the stop watch clock</span>
sw.Start();

<span class="hljs-comment">// run your code</span>
<span class="hljs-keyword">var</span> sum = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">100</span>; i++)
{
    sum += i * i;
    Console.WriteLine(<span class="hljs-string">$"<span class="hljs-subst">{sw.ElapsedMilliseconds}</span>"</span>);
}
<span class="hljs-comment">// Stop the clock !</span>
sw.Stop();

<span class="hljs-comment">// Output total time elapsed on the Stopwatch.</span>
Console.WriteLine(<span class="hljs-string">$"Elapsed time: <span class="hljs-subst">{sw.ElapsedMilliseconds}</span> ms"</span>);
</code></pre>
<p>This would print out how many milliseconds have elapsed on each iteration as well as the end elapsed milliseconds. As this is a short program, you can convert to nanoseconds by using <code>ticks</code> like so:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">long</span> ticks = stopwatch.ElapsedTicks;
<span class="hljs-keyword">double</span> nanoseconds = (ticks * <span class="hljs-number">1e9</span>) / Stopwatch.Frequency;
</code></pre>
<p>Using a stopwatch can be useful if you want to quickly compare two methods or identify obvious performance bottlenecks during development. It’s a lightweight way to get an initial sense of which sections of code might need optimization.</p>
<h3 id="heading-cons-of-stopwatch">Cons of Stopwatch</h3>
<ul>
<li><p>Lack of precision by default, being only accurate to around 100 nanoseconds, which may not be useful for smaller quick micro operations.</p>
</li>
<li><p>JIT (Just in Time) compilation - When code runs for the first time, a JIT compiler compiles the code before running, causing a delay and skewing the timing of completion. Subsequent runs of the code will be slightly faster, however, <code>Stopwatch</code> does not account for this. Keeping this in mind, it is worth running the code a few times to try and alleviate this problem.</p>
</li>
<li><p>Garbage Collection (GC) - If garbage collection happens during a <code>Stopwatch</code> measurement, the time recorded will include GC pause time, which does not reflect the actual execution time of your code.</p>
</li>
</ul>
<p>These are just some of the basic, and most common flaws of using a <code>Stopwatch</code> to test the performance of your code but there are others.  </p>
<p>So what is the best approach?</p>
<p><strong>BenchmarkDotNet</strong> is a popular and robust library for benchmarking in .NET, which can be installed using <code>nuget</code>.</p>
<p>It overcomes many of the above challenges, in the following ways:</p>
<ul>
<li><p>Code Warm Ups - Automatically warms up the code (by running the code a few times) to avoid JIT-related inaccuracies.</p>
</li>
<li><p>Multiple code iterations - Runs the code multiple times to analyze and calculates statistical summaries, around execution time, heap memory allocation and more. The number of times the code is ran can be configured.</p>
</li>
<li><p>Isolated Environments - Manages garbage collection and isolates the execution environment to reduce external interference.</p>
</li>
</ul>
<h2 id="heading-how-to-use-benchmarkdotnet">How to Use BenchMarkDotnet</h2>
<p>Firstly, we need to install the Nuget package. To do this, run the following command in your command line/terminal:</p>
<pre><code class="lang-plaintext">dotnet add package BenchmarkDotnet
</code></pre>
<p>We then need some methods to benchmark, so create a .Net 8 C# console app with the following two class files:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>
<span class="hljs-keyword">using</span> BenchmarkDotNet.Running;

BenchmarkRunner.Run&lt;Benchmarks&gt;();
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">//Benchmarks.cs</span>
<span class="hljs-keyword">using</span> BenchmarkDotNet.Attributes;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Benchmarks</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">int</span>[] _numbers = Enumerable.Range(<span class="hljs-number">1</span>, <span class="hljs-number">1000</span>).ToArray();

    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">ForLoopSum</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">int</span> sum = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; _numbers.Length; i++)
        {
            sum += _numbers[i];
        }

        <span class="hljs-keyword">return</span> sum;
    }

    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">ForeachLoopSum</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> sum = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">int</span> number <span class="hljs-keyword">in</span> _numbers)
        {
            sum += number;
        }

        <span class="hljs-keyword">return</span> sum;
    }

    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">LinqSelect</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">return</span> _numbers.Sum();
    }
}
</code></pre>
<p>Above, we have 3 different methods to add up an array of integers, each doing so in a slightly different fashion. This is a perfect example to show how benchmarking can aid us to choose the best solution in our code base.</p>
<h3 id="heading-how-to-run-the-benchmarks">How to Run the Benchmarks</h3>
<p>To run the benchmarks, you can run the following commands in your terminal/command line.</p>
<pre><code class="lang-bash">dotnet build
<span class="hljs-comment"># then run </span>
dotnet run -c Release
</code></pre>
<p>BenchmarkDotnet will then run the methods marked with the <code>[Benchmark]</code> attribute multiple times, and will output the results in an easy to read table, like so:</p>
<pre><code class="lang-bash">| Method         | Mean     | Error   | StdDev  |
|--------------- |---------:|--------:|--------:|
| ForLoopSum     | 434.2 ns | 0.40 ns | 0.31 ns |
| ForeachLoopSum | 321.9 ns | 1.22 ns | 1.14 ns |
| LinqSelect     | 189.4 ns | 0.84 ns | 0.70 ns |
</code></pre>
<p>What does this mean?</p>
<p><strong>Method</strong> - Name of the method under test  </p>
<p><strong>Mean</strong> - Shows the mean (average) time it took in nanoseconds.  </p>
<p><strong>Error</strong> - Represents the margin of error, telling you how much the "Mean" result might vary due to random factors in the system. The lower the number the better, here you can see a very small margin of error meaning the results are stable, whilst large numbers would mean more uncertainty/ unreliable results.</p>
<p><strong>StdDev -</strong> (Standard Deviation) shows how consistent the benchmark results are. A low deviation score indicates the time taken was very similar across multiple runs, increasing reliability. If the standard deviation is high, it would mean the method’s execution time varied a lot between runs.</p>
<h3 id="heading-how-to-measure-memory-allocation">How to Measure Memory Allocation</h3>
<p>Knowing how fast your methods run is a great statistic to understand and know. However, your performance and optimization isn’t just about the time of execution, sometimes you should ensure that there are no memory leaks or large sums of memory utilized, especially with large execution process.</p>
<p>We can use the <code>[MemoryDiagnoser]</code> to the <code>Benchmarks</code> class, which informs the benchmarking library to include memory statistics to the methods under test.</p>
<p>When we run our benchmarks, we get the following output:</p>
<pre><code class="lang-bash">| Method         | Mean     | Error   | StdDev  | Allocated |
|--------------- |---------:|--------:|--------:|----------:|
| ForLoopSum     | 436.8 ns | 5.32 ns | 4.98 ns |         - |
| ForeachLoopSum | 324.6 ns | 2.20 ns | 2.06 ns |         - |
| LinqSelect     | 192.7 ns | 2.40 ns | 2.24 ns |         - |
</code></pre>
<p>But wait, the <strong>Allocated</strong> column has but a dash ? Where are the results?</p>
<p>Simple operations, like summing values in an array generally don’t allocate memory, as they often only use stack memory, which BenchmarkDotNet doesn’t track in the same way.</p>
<p>But using the following tests, we can see how memory allocation can be analyzed:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MemoryBenchmark</span>
{
    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">StringConcatenation</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">string</span> result = <span class="hljs-string">""</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000</span>; i++)
        {
            result += <span class="hljs-string">"text"</span>;
        }
        <span class="hljs-keyword">return</span> result;
    }

    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">StringBuilderConcatenation</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> builder = <span class="hljs-keyword">new</span> System.Text.StringBuilder();
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000</span>; i++)
        {
            builder.Append(<span class="hljs-string">"text"</span>);
        }
        <span class="hljs-keyword">return</span> builder.ToString();
    }
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">| Method                     | Mean       | Error     | StdDev    | Gen0     | Allocated  |
|--------------------------- |-----------:|----------:|----------:|---------:|-----------:|
| StringConcatenation        | 218.930 us | 0.7230 us | 0.6409 us | 641.8457 | 3933.56 KB |
| StringBuilderConcatenation |   1.645 us | 0.0034 us | 0.0030 us |   2.6875 |   16.47 KB |
</code></pre>
<p>Here we have 2 new columns:<br><strong>Gen0 Column:</strong><br>The <strong>Gen0</strong> column indicates how many Gen 0 garbage collections occurred during each method’s execution.  </p>
<p>.Net uses a generational garbage collection system, where memory is divided into three "generations" (Gen0, Gen1, and Gen2).</p>
<ul>
<li><p><strong>Gen0 (Generation 0)</strong>: Holds short-lived objects, such as temporary variables and small, quickly discarded objects. Gen0 collections are the fastest type of GC but still introduce some overhead. Examples of Gen0 would be local variables in methods, temporary objects, or method call arguments that aren’t used later on.</p>
</li>
<li><p><strong>Gen1 and Gen2</strong>: This is for longer-lived objects that survive Gen0 collections, like static objects that are kept alive for the lifetime of the application (that is, singletons), caching objects or large collections used across many operations.</p>
</li>
</ul>
<p>Objects in <strong>Gen0</strong> are collected quickly but often, and objects in <strong>Gen2</strong> are collected infrequently but with more effort because they are larger or more persistent. A lot of <strong>Gen0</strong> collections can be an indicator of inefficient memory usage, while <strong>Gen2 or 3</strong> collections may indicate that your app is keeping too many long-lived objects in memory.</p>
<p><strong>Allocated Column:</strong><br>The <strong>Allocated</strong> column shows the total memory allocated by each method during its execution. This is typically reported in kilobytes (KB).</p>
<p>This information helps you see how memory-intensive each method is, which can impact performance, especially if the method is called frequently.</p>
<p>For example, <code>StringBuilderConcatenation</code> is much more memory-efficient than <code>StringConcatenation</code>, which makes it preferable in cases where memory usage is a concern or where this operation is performed frequently.</p>
<h2 id="heading-what-else-can-you-test-with-benchmarkdotnet">What Else Can You Test with BenchmarkDotnet?</h2>
<h3 id="heading-throughput">Throughput</h3>
<ul>
<li><p>Analyzes how many iterations of a method can be executed per second.</p>
</li>
<li><p>Indicates the efficiency and scalability of the code.</p>
</li>
</ul>
<h3 id="heading-jit-just-in-time-optimization-impact">JIT (Just-In-Time) Optimization Impact</h3>
<ul>
<li><p>Evaluates the effects of JIT optimizations on performance.</p>
</li>
<li><p>Can test cold starts (first-run performance) versus steady-state performance (subsequent runs).</p>
</li>
</ul>
<h3 id="heading-platform-and-framework-differences">Platform and Framework Differences</h3>
<p>You could run benchmarks of the same code across different .NET runtimes (for example, .NET 6, .NET 8, .NET Framework) to compare whether it’s worth upgrading your application to newer systems or not.</p>
<p>Simply update the TargetFramework node in the <code>.csproj</code> file of your application to target the frameworks you wish to test.</p>
<p>Add the following attributes to your benchmark class (based on the target runtime).</p>
<pre><code class="lang-bash">[SimpleJob(runtimeMoniker: RuntimeMoniker.Net60)]
[SimpleJob(runtimeMoniker: RuntimeMoniker.Net80)]
</code></pre>
<p>when you run your application you will get an output as below highlighting the differenes in methods across both .net 6 and .net 8</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Method</td><td>Job</td><td>Runtime</td><td>Mean</td><td>Error</td><td>StdDev</td></tr>
</thead>
<tbody>
<tr>
<td>StringConcatenation</td><td>.NET 6.0</td><td>.NET 6.0</td><td>286.503 us</td><td>3.5004 us</td><td>3.1030 us</td></tr>
<tr>
<td>StringBuilderConcatenation</td><td>.NET 6.0</td><td>.NET 6.0</td><td>4.595 us</td><td>0.0620 us</td><td>0.0580 us</td></tr>
<tr>
<td>StringConcatenation</td><td>.NET 8.0</td><td>.NET 8.0</td><td>222.270 us</td><td>1.7561 us</td><td>1.4664 us</td></tr>
<tr>
<td>StringBuilderConcatenation</td><td>.NET 8.0</td><td>.NET 8.0</td><td>1.650 us</td><td>0.0139 us</td><td>0.0116 us</td></tr>
</tbody>
</table>
</div><h3 id="heading-impact-of-input-parameters">Impact of Input Parameters</h3>
<ul>
<li><p>Supports parameterized benchmarks to test how different inputs affect performance.</p>
</li>
<li><p>Helps identify optimal input ranges or problematic edge cases.</p>
</li>
</ul>
<p>You can do something like this</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> BenchmarkDotNet.Attributes;
<span class="hljs-keyword">using</span> BenchmarkDotNet.Running;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SortBenchmark</span>
{
    [<span class="hljs-meta">Params(10, 100, 1000)</span>]  <span class="hljs-comment">// Size of the array</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> N;

    [<span class="hljs-meta">Params(10, 100, 1000)</span>]  <span class="hljs-comment">// Maximum value of the array elements</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> MaxValue;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span>[] data;

    <span class="hljs-comment">// Setup method to create an array before each benchmark</span>
    [<span class="hljs-meta">GlobalSetup</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Setup</span>(<span class="hljs-params"></span>)</span>
    {
        data = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[N];
        <span class="hljs-keyword">var</span> rand = <span class="hljs-keyword">new</span> Random();
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; N; i++)
        {
            data[i] = rand.Next(MaxValue);
        }
    }

    [<span class="hljs-meta">Benchmark</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SortArray</span>(<span class="hljs-params"></span>)</span>
    {
        Array.Sort(data);  <span class="hljs-comment">// Sort the array</span>
    }
}

<span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-comment">// Run the benchmark</span>
        BenchmarkRunner.Run&lt;SortBenchmark&gt;();
    }
}
</code></pre>
<p>Giving the output of:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Method</td><td>N</td><td>MaxValue</td><td>Mean</td><td>Error</td><td>StdDev</td><td>Allocated</td></tr>
</thead>
<tbody>
<tr>
<td>SortArray</td><td>10</td><td>10</td><td>3.5 ns</td><td>0.1 ns</td><td>0.05 ns</td><td>0 B</td></tr>
<tr>
<td>SortArray</td><td>10</td><td>1000</td><td>4.0 ns</td><td>0.2 ns</td><td>0.1 ns</td><td>0 B</td></tr>
<tr>
<td>SortArray</td><td>100</td><td>10</td><td>20.1 ns</td><td>0.5 ns</td><td>0.3 ns</td><td>0 B</td></tr>
<tr>
<td>SortArray</td><td>100</td><td>1000</td><td>25.2 ns</td><td>0.8 ns</td><td>0.4 ns</td><td>0 B</td></tr>
<tr>
<td>SortArray</td><td>1000</td><td>10</td><td>300.3 ns</td><td>5.6 ns</td><td>2.7 ns</td><td>0 B</td></tr>
<tr>
<td>SortArray</td><td>1000</td><td>1000</td><td>320.1 ns</td><td>6.3 ns</td><td>3.1 ns</td><td>0 B</td></tr>
</tbody>
</table>
</div><h3 id="heading-third-party-library-performance">Third-Party Library Performance</h3>
<p>Using the techniques mentioned above, you can compare the performance of different third-party libraries for the same task to make informed decisions on library usage.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>There you have it, how to benchmark your C# application. Using a combination of these methods, tools and techniques, the possibilities of benchmarking are incredible.</p>
<p>You can use benchmarking to improve your application’s code base, help make decisions on upgrade paths, and method choices.</p>
<p>I hope you find this article helpful, and as always, if you wish to discuss it you can follow me on <a target="_blank" href="https://x.com/grantdotdev">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Extension Methods in C# ]]>
                </title>
                <description>
                    <![CDATA[ Extension methods are a fundamental part of C# and Object Oriented Programming (OOP). Extension methods in C# allow you to "extend" existing types, including classes, interfaces, or structs, without modifying their original code. This is particularly... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-extension-methods-in-csharp/</link>
                <guid isPermaLink="false">6722f316b717c1a9c6f35b34</guid>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Thu, 31 Oct 2024 03:01:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730322390431/42cfe64d-0fce-4f36-a4f7-25e1e56267a4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Extension methods are a fundamental part of C# and Object Oriented Programming (OOP). Extension methods in C# allow you to "extend" existing types, including classes, interfaces, or structs, without modifying their original code.</p>
<p>This is particularly useful when you want to add new functionality to a type you don't own or can't change, like types from third-party libraries or built-in .NET types such as <code>string</code>, <code>List&lt;T&gt;</code>, and so on.</p>
<p>In this article, you’ll learn how to add extension methods to your classes, as well as third-party and system classes.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-create-datetime-extension-methods">How to Create DateTime Extension Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-chain-same-type-extension-methods">How to Chain Same-Type Extension Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-cant-i-just-add-these-methods-to-my-class">Why Can’t I Just Add These Methods to My Class?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-extensions">When to Use Extensions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-not-to-use-extension-methods">When Not to Use Extension Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-things-to-consider-when-designing-extensions">Things to Consider When Designing Extensions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-how-to-create-datetime-extension-methods">How to Create DateTime Extension Methods</h2>
<p>Let’s say we want some methods that can be used along with the existing <code>DateTime</code> class, perhaps a method that returns whether the given <code>DateTime</code> object is a weekend or something different.</p>
<p>Extension methods need to be defined in a static class because they are essentially syntactic sugar that allows you to call a static method as if it were an instance method on the type you're extending.</p>
<p>Extension methods need to be in a static class because:</p>
<ol>
<li><p><strong>No Object Needed:</strong> You don’t need to create an object to use an extension method. Since the method adds new functionality to an existing type (like <code>string</code>), it can work without needing an instance of the class.</p>
</li>
<li><p><strong>Organized Code:</strong> Putting extension methods in a static class keeps things tidy. It allows you to group related methods, and you can easily include them in your code by using the appropriate namespace.</p>
</li>
</ol>
<p>So, by using a static class, you can add useful methods to existing types without changing their original code, and you don’t need an object to call them.</p>
<p>First, let’s create a <code>DateTimeExtensions</code> static class.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DateTimeExtensions</span> {

}
</code></pre>
<p>This will encompass all the <code>DateTime</code> extensions we want to create.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">IsWeekend</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> DateTime date</span>)</span>
{
    <span class="hljs-keyword">return</span> date.DayOfWeek <span class="hljs-keyword">is</span> DayOfWeek.Saturday or DayOfWeek.Sunday;
}
</code></pre>
<p><strong>Explanation:</strong></p>
<p><code>public static bool IsWeekend</code>: This defines that it is a static method called <code>IsWeekend</code> which will return a <code>bool</code> value (true/false).</p>
<p><code>this DateTime date</code>: The <code>this</code> keyword as a method argument denotes that this method is an extension method. It means that the method will be an extension of the <code>DateTime</code> class.</p>
<h2 id="heading-how-to-chain-same-type-extension-methods">How to Chain Same-Type Extension Methods</h2>
<p>For an extension method to be chained with others, it typically needs to return the same type as the one it's extending (or a compatible type). This allows another method to be called on the result of the previous one.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Globalization;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">ToTitleCase</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> <span class="hljs-keyword">string</span> str</span>)</span>
{
    <span class="hljs-keyword">return</span> CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">TrimAndAppend</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> <span class="hljs-keyword">string</span> str, <span class="hljs-keyword">string</span> toAppend</span>)</span>
{
    <span class="hljs-keyword">return</span> str.Trim() + toAppend;
}
</code></pre>
<p>In the above example, both the <code>ToTitleCase</code> and <code>TrimAndAppend</code> methods return a string value, meaning that we can chain the extension methods as below, which will convert the string to title-case before trimming all whitespace and appending the provided string.</p>
<p>Notice that we only provided the second parameter to the <code>TrimAndAppend</code> method, as the first parameter is the string having the extension method applied to (as explained previously, denoted by the <code>this</code> keyword).</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> title = <span class="hljs-string">"hello world   "</span>
    .ToTitleCase()
    .TrimAndAppend(<span class="hljs-string">"!!"</span>);

<span class="hljs-comment">//Output:</span>
<span class="hljs-comment">// Hello World!!</span>
</code></pre>
<p>If the extension method returns a different type (not the original one or a compatible type), you cannot chain it. For example:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> date = <span class="hljs-keyword">new</span> DateTime();
date.IsWeekend().AddDays(<span class="hljs-number">1</span>);
</code></pre>
<p>For less obvious reasons, this will not work. When you chain methods, they do not chain from the original variable—they chain from the return type of the previous method call.  </p>
<p>Here, we have a date called <code>IsWeekend()</code> which returns a Boolean. We then attempted to call <code>AddDays(1)</code> on a Boolean value which doesn’t exist, as it is a <code>DateTime</code> extension. The code compiler will fail to build, raising an error informing you of this.</p>
<h3 id="heading-how-to-return-the-instance-to-chain">How to Return the Instance to Chain</h3>
<p>In some extension methods, especially those for configuration (like Dependency Injection), you return the same instance to allow method chaining. This lets you continue working with the original object or its modified state across multiple calls, enabling a fluent interface.</p>
<p>Let’s take the example of a list of cars.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">RemoveDuplicates</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> List&lt;T&gt; list</span>)</span>
{
    <span class="hljs-comment">// Use Distinct to remove duplicates and update the list</span>
    list = list.Distinct().ToList();

    <span class="hljs-comment">// Return the modified list to allow method chaining</span>
    <span class="hljs-keyword">return</span> list;
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">List</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-title">AddRangeOfItems</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> List&lt;T&gt; list, IEnumerable&lt;T&gt; items</span>)</span>
{
    <span class="hljs-comment">// Add a range of items to the list</span>
    list.AddRange(items);

    <span class="hljs-comment">// Return the modified list to allow method chaining</span>
    <span class="hljs-keyword">return</span> list;  
}
</code></pre>
<p>Now that we’ve returned the list from these extension methods, we can chain additional methods on the same list. For example, after removing duplicates with <code>RemoveDuplicates()</code>, we can immediately call <code>AddRangeOfItems()</code> on the same list.</p>
<p>So we can do something like:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> existingStock = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt; { <span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Jaguar"</span>, <span class="hljs-string">"Ferrari"</span>, <span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Renault"</span> };

<span class="hljs-keyword">var</span> availableBrands = existingStock
    .RemoveDuplicates()
    .AddRangeOfItems(<span class="hljs-keyword">new</span>[] { <span class="hljs-string">"Lamborghini"</span> }); <span class="hljs-comment">// new stock available</span>

Console.WriteLine(<span class="hljs-string">"Brands Available Now: "</span> + <span class="hljs-keyword">string</span>.Join(<span class="hljs-string">", "</span>, availableBrands));

<span class="hljs-comment">// Output: Brands Available Now: Ford, Jaguar, Ferrari, Renault, Lamborghini</span>
</code></pre>
<p>We removed duplicates from a list of car brands and added new stock to the same list. This works because <code>RemoveDuplicates</code> returns the list, enabling us to chain it with <code>AddRangeOfItems</code>.</p>
<p>If <code>RemoveDuplicates</code> returned <code>void</code> instead of the list, we wouldn't be able to chain the methods. It would still remove duplicates, but further actions like adding new stock, wouldn't be possible in the same expression.</p>
<p>We’d also have to update the <code>RemoveDuplicates</code> to update the list argument passed in, as <code>Distinct()</code> returns a new list which isn’t being returned as shown below, which I think you’ll agree is a lot more verbose.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RemoveDuplicates</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> List&lt;T&gt; list</span>)</span>
{
    <span class="hljs-comment">// Get the distinct elements and clear the original list</span>
    <span class="hljs-keyword">var</span> distinctItems = list.Distinct().ToList();
    list.Clear(); 

    <span class="hljs-comment">// Add the distinct items back to the original list</span>
    list.AddRange(distinctItems);
}
</code></pre>
<h2 id="heading-why-cant-i-just-add-these-methods-to-my-class">Why Can’t I Just Add These Methods to My Class?</h2>
<p>If the method is not a core part of the class’s functionality, placing it in an extension method can help keep the class focused and maintainable.</p>
<p><strong>Separation of Concerns</strong>: Using extension methods keeps your code cleaner, and helps reduce complexity<strong>.</strong> It helps avoid bloating the class with methods that may not be used frequently.</p>
<p><strong>Enhancing External Libraries</strong>: If you’re using a library or framework where you cannot modify the source code, extension methods allow you to add functionality to those types without altering their definitions.</p>
<p>Let’s say you’re using the <code>FileInfo</code> class from the <a target="_blank" href="http://System.IO"><code>System.IO</code></a> namespace to work with files. You may want to add a method to easily check if a file is too large (for example, more than 1 GB), but you cannot modify the <code>FileInfo</code> class directly because it belongs to the System.IO namespace (that is, it's baked into .Net).</p>
<p><strong>Without an extension:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> fileInfo = <span class="hljs-keyword">new</span> FileInfo(<span class="hljs-string">"myFile.txt"</span>);

<span class="hljs-keyword">if</span> (fileInfo.Length &gt; <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span>) <span class="hljs-comment">// filesize is bigger than 1GB</span>
{
    Console.WriteLine(<span class="hljs-string">"The file is too large."</span>);
}
<span class="hljs-keyword">else</span>
{
    Console.WriteLine(<span class="hljs-string">"The file size is acceptable."</span>);
}
</code></pre>
<p><strong>With Extension Method:</strong></p>
<p>You can make this more reusable by adding an extension method that checks whether the file is larger than 1 GB.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">FileInfoExtensions</span>
{
    <span class="hljs-comment">//extension method, with default file size of 1GB (can be overriden)</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">IsFileTooLarge</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> FileInfo fileInfo, <span class="hljs-keyword">long</span> sizeInBytes = <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span></span>)</span>
    {
        <span class="hljs-keyword">return</span> fileInfo.Length &gt; sizeInBytes;
    }
}
</code></pre>
<p>Now you can use the <code>IsFileTooLarge</code> method directly on <code>FileInfo</code> objects, making your code cleaner:</p>
<pre><code class="lang-csharp">csharpCopy codevar fileInfo = <span class="hljs-keyword">new</span> FileInfo(<span class="hljs-string">"myFile.txt"</span>);

<span class="hljs-keyword">if</span> (fileInfo.IsFileTooLarge())
{
    Console.WriteLine(<span class="hljs-string">"The file is too large."</span>);
}
<span class="hljs-keyword">else</span>
{
    Console.WriteLine(<span class="hljs-string">"The file size is acceptable."</span>);
}
</code></pre>
<p>Extending third-party libraries and packages can make your code much more compatible.</p>
<p><strong>Better Organization &amp; Readability</strong>: You can organize extension methods into static classes based on functionality or context, making it easier to find and use them. This is certainly enhanced by allowing extension methods to be chained.</p>
<h2 id="heading-when-to-use-extensions">When to Use Extensions</h2>
<ul>
<li><p><strong>For Utility Methods:</strong> If you have utility methods that are useful for a type but don’t belong directly in the type itself (for example, formatting, validation).</p>
</li>
<li><p><strong>For Enhancing Built-In Types:</strong> If you want to add functionality to built-in types (like <code>string</code> or <code>DateTime</code>) without modifying them.</p>
</li>
<li><p><strong>When You Want to Keep Methods Optional:</strong> If you want to provide additional methods that users can opt to use without forcing them to incorporate them into the main class design.</p>
</li>
</ul>
<h3 id="heading-example-scenario"><strong>Example Scenario</strong></h3>
<p>Imagine that you have a <code>Person</code> class, and you want to add a method to format the person's name nicely:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Person</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> FirstName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> LastName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}

<span class="hljs-comment">// Extension method in a static class</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PersonExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetFullName</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> Person person</span>)</span>
    {
        <span class="hljs-keyword">return</span> <span class="hljs-string">$"<span class="hljs-subst">{person.FirstName}</span> <span class="hljs-subst">{person.LastName}</span>"</span>;
    }
}
</code></pre>
<p>By using an extension method for <code>GetFullName</code>, you can keep the <code>Person</code> class simple and focused on its core responsibilities, while still providing useful functionality.</p>
<h2 id="heading-when-not-to-use-extension-methods">When Not to Use Extension Methods</h2>
<ul>
<li><p><strong>For Core Functionality:</strong> If a method is essential to a class's core behavior, it should be part of the class itself, not an extension.</p>
</li>
<li><p><strong>For Tight Coupling:</strong> If the extension method requires intimate knowledge of the class's private state or needs regular access to its internal logic.</p>
</li>
<li><p><strong>For Public APIs:</strong> When designing a public-facing library or API, it's often better to include necessary methods directly in the class rather than forcing users to find or create their extension methods.</p>
</li>
</ul>
<h2 id="heading-things-to-consider-when-designing-extensions">Things to Consider When Designing Extensions</h2>
<p>While extension methods are powerful and convenient in many cases, there are certain cons or situations where using them might not be the best choice:</p>
<h3 id="heading-hidden-behaviorconfusion">Hidden Behavior/Confusion</h3>
<ul>
<li><p>Extension methods don't appear directly in the class definition, meaning that they can be harder to discover by developers who are unfamiliar with the available extensions.</p>
</li>
<li><p>Developers need to know that these extension methods exist, or they might miss using them unless they are working in an IDE with features like IntelliSense (for example, Visual Studio, JetBrains Rider). These IDEs can suggest extension methods from other files or namespaces as they detect the appropriate type. Without a feature-rich IDE, the developer would have to be aware of the extension methods or find the folder they’re stored in.</p>
</li>
</ul>
<h3 id="heading-cant-access-private-members"><strong>Can’t Access Private Members</strong></h3>
<ul>
<li><p>Extension methods can only access members (methods, properties, fields) that are public or internal.</p>
</li>
<li><p>They cannot access private or protected members of a class because extension methods operate as if they are part of the class from the outside, similar to regular method calls from outside the class.</p>
</li>
</ul>
<p><strong>Example:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> engineNumber = <span class="hljs-string">"12345"</span>; <span class="hljs-comment">// Private field</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Brand { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-string">"Ford"</span>; <span class="hljs-comment">// Public property</span>

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartEngine</span>(<span class="hljs-params"></span>) <span class="hljs-comment">// Private method</span></span>
    {
        Console.WriteLine(<span class="hljs-string">"Engine started"</span>);
    }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CarExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DisplayBrand</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> Car car</span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"Brand: <span class="hljs-subst">{car.Brand}</span>"</span>); <span class="hljs-comment">// Accessing the public 'Brand' property</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">TryAccessPrivateField</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> Car car</span>)</span>
    {
        <span class="hljs-comment">// Cannot access the private 'engineNumber'</span>
        <span class="hljs-comment">// This will result in a compile-time error.</span>
        Console.WriteLine(car.engineNumber);
    }
}
</code></pre>
<h3 id="heading-code-duplication-amp-overuse"><strong>Code Duplication &amp; Overuse</strong></h3>
<ul>
<li><p>In some cases, extension methods can encourage code duplication. If multiple projects or classes require similar extension methods, you might end up writing or copying the same extension methods in different places, making it harder to manage and update the code consistently.  </p>
<p>  To avoid this, organize your code effectively. I would recommend keeping all extensions within an extensions folder or project, close to the origin (depending on the design patterns being used within your application).</p>
</li>
</ul>
<ul>
<li><strong>Abuse of Extensions:</strong> If used excessively, they can clutter the global space with methods that might not need to be global. This can cause pollution of the type’s API, making it harder to understand what’s core to the class versus what’s added via extensions.</li>
</ul>
<p>    In some cases, it's better to encapsulate functionality in a separate helper classes or services rather than adding it via extension methods.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Extension methods are useful for adding functionality in a clean and modular way, but they can also introduce confusion, namespace conflicts, and lack of access to private members.</p>
<p>As highlighted throughout the article, they have many usages and are certainly a very nice feature of the Dotnet framework when used effectively. They should be used when appropriate, but not as a substitute for functionality that belongs within the class itself.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are the SOLID Principles in C#? Explained With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand these five... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-the-solid-principles-in-csharp/</link>
                <guid isPermaLink="false">671a62b68210490d9d68e83f</guid>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 24 Oct 2024 15:07:34 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729777076695/7d956373-1835-4823-9a6a-d2d232cd64d5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand these five principles.</p>
<p>The SOLID Principles were introduced by a software engineer named Robert C. Martin (also known as "Uncle Bob") in the early 2000s. Uncle Bob’s goal was to promote good software design practices, particularly in object-oriented programming (OOP), by addressing common problems developers face as software systems grow in size and complexity.</p>
<p>Here are the five SOLID principles:</p>
<ul>
<li><p><strong>S</strong>: <a class="post-section-overview" href="#heading-single-responsibility-principle-srp">Single Responsibility Principle (SRP)</a></p>
</li>
<li><p><strong>O</strong>: <a class="post-section-overview" href="#heading-open-closed-principle-ocp">Open-closed Principle (OCP)</a></p>
</li>
<li><p><strong>L</strong>: <a class="post-section-overview" href="#heading-liskov-substitution-principle-lsp">Liskov Substitution Principle (LSP)</a></p>
</li>
<li><p><strong>I</strong>: <a class="post-section-overview" href="#heading-interface-segregation-principle-isp">Interface Segregation Principle (ISP)</a></p>
</li>
<li><p><strong>D</strong>: <a class="post-section-overview" href="#heading-dependency-inversion-principle-dip">Dependency Inversion Principle (DIP)</a></p>
</li>
</ul>
<p>By following these principles, you can create software designs that are easier to understand, maintain, and extend, leading to higher-quality software that is more robust and adaptable to change.</p>
<p>In this article, to demonstrate each principle, I’ll first show you a bad code example in C# that violates the principle. We will then discuss the issues this bad code causes, and then solve those issues by refactoring the code to satisfy the principle.</p>
<p>First up we have the…</p>
<h2 id="heading-single-responsibility-principle-srp-in-c">Single Responsibility Principle (SRP) in C</h2>
<blockquote>
<p>A class should have only one reason to change, meaning that it should have only one responsibility or purpose.</p>
</blockquote>
<p>This principle encourages you to create classes that are more focussed and perform one single well-defined task, rather than multiple tasks. Breaking up classes into smaller, more focused units makes code easier to understand, maintain, and test.</p>
<p><strong>An example that violates the SRP:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Register</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-comment">// Register user logic, e.g. save to database...</span>

   <span class="hljs-comment">// Send email notification</span>
   EmailSender emailSender = <span class="hljs-keyword">new</span> EmailSender();
   emailSender.SendEmail(<span class="hljs-string">"Welcome to our platform!"</span>, Email);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmailSender</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">string</span> recipient</span>)</span>
 {
   <span class="hljs-comment">// Email sending logic</span>
   Console.WriteLine(<span class="hljs-string">$"Sending email to <span class="hljs-subst">{recipient}</span>: <span class="hljs-subst">{message}</span>"</span>);
 }
}
</code></pre>
<p>In this example, the <code>User</code> class manages user data (username and email), and contains logic for registering a user. This violates the SRP because the class has more than one reason to change. It could change due to:</p>
<ul>
<li><p>Modifications in user data management – for example adding more fields, such as <code>firstName</code>, <code>gender</code>, <code>hobbies</code>.</p>
</li>
<li><p>Modifications to the logic of registering a user, for example we may choose to fetch a user from the database by their username rather than their email.</p>
</li>
</ul>
<p>To adhere to the Single Responsibility Principle, we should separate these responsibilities into separate classes. </p>
<p><strong>Refactoring the code to satisfy the SRP</strong>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmailSender</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">string</span> recipient</span>)</span>
 {
   <span class="hljs-comment">// Email sending logic</span>
   Console.WriteLine(<span class="hljs-string">$"Sending email to <span class="hljs-subst">{recipient}</span>: <span class="hljs-subst">{message}</span>"</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RegisterUser</span>(<span class="hljs-params">User user</span>)</span>
 {
   <span class="hljs-comment">// Register user logic...</span>

   EmailSender emailSender = <span class="hljs-keyword">new</span> EmailSender();
   emailSender.SendEmail(<span class="hljs-string">"Welcome to our platform!"</span>, user.Email);
 }
}
</code></pre>
<p>In the refactored code, the <code>User</code> class is responsible solely for representing user data. The <code>UserService</code> class now handles user registration, separating concerns related to user data management from user registration logic. The <code>UserService</code> class is responsible only for the business logic of registering a user.</p>
<p>This separation of responsibilities adheres to the Single Responsibility Principle, making the code easier to understand, maintain, and extend.</p>
<h2 id="heading-openclosed-principle-ocp-in-c">Open/Closed Principle (OCP) in C</h2>
<blockquote>
<p>Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.</p>
</blockquote>
<p>This principle promotes the idea that existing code should be able to be extended with new functionality without modifying its source code. It encourages the use of abstraction and polymorphism to achieve this goal, allowing for code to be easily extended through inheritance or composition.</p>
<p>(By the way, if you don’t understand these fundamental OOP concepts, such as abstraction, polymorphism, inheritance and composition — then check out my book, <a target="_blank" href="https://www.amazon.com/Mastering-Design-Patterns-Beginner-Friendly-Principles/dp/B0DB6MLYYZ">Mastering Design Patterns in C#: A Beginner-Friendly Guide, Including OOP and SOLID Principles on Amazon</a> or <a target="_blank" href="https://doabledanny.gumroad.com/l/ennyj?layout=profile">Gumroad</a>.)</p>
<p>Let's consider an example of a <code>Shape</code> class hierarchy that calculates the area of different geometric shapes. Initially, this violates the Open/Closed Principle because adding a new shape requires modifying the existing code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">enum</span> ShapeType
{
 Circle,
 Rectangle
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> ShapeType Type { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Length { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">switch</span> (Type)
   {
     <span class="hljs-keyword">case</span> ShapeType.Circle:
       <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
     <span class="hljs-keyword">case</span> ShapeType.Rectangle:
       <span class="hljs-keyword">return</span> Length * Width;
     <span class="hljs-keyword">default</span>:
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Unsupported shape type."</span>);
   }
 }
}
</code></pre>
<p>In this example, the <code>Shape</code> class has a method, <code>CalculateArea()</code>, that calculates the area based on the type of shape. Adding a new shape, such as a triangle, would require modifying the existing <code>Shape</code> class, violating the OCP.</p>
<p>To adhere to the Open/Closed Principle, we should design the system in a way that allows for extension without modification. Let's refactor the code using inheritance and polymorphism:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Length { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Length * Width;
 }
}
</code></pre>
<p>In this refactored code, we define an abstract <code>Shape</code> class with an abstract <code>CalculateArea()</code> method. Concrete shape classes (<code>Circle</code> and <code>Rectangle</code>) inherit from the <code>Shape</code> class and provide their own implementations of <code>CalculateArea()</code>.</p>
<p>Adding a new shape, such as a triangle, would involve creating a new class – <em>extending</em> the codebase – that inherits from <code>Shape</code> and implements <code>CalculateArea()</code>, without <em>modifying</em> existing code. This adheres to the OCP by allowing for extension without modification.</p>
<p>Being able to add functionality without modifying existing code means that we don’t have to worry as much about breaking existing working code and introducing bugs.</p>
<p>Following the OCP encourages us to design our software so that we add new features only by adding new code. This helps us to build loosely-coupled, maintainable software.</p>
<h2 id="heading-liskov-substitution-principle-lsp-in-c">Liskov Substitution Principle (LSP) in C</h2>
<blockquote>
<p>Objects of a superclass should be replaceable with objects of its subclass without affecting the correctness of the program.</p>
</blockquote>
<p>This principle ensures that inheritance hierarchies are well-designed and that subclasses adhere to the contracts defined by their superclasses.</p>
<p>Violations of the LSP can lead to unexpected behavior or errors when substituting objects, making code harder to reason about and maintain.</p>
<p>Let's consider an example involving a <code>Rectangle</code> class and a <code>Square</code> class, which inherit from a common <code>Shape</code> class. Initially, we'll violate the LSP by not adhering to the behavior expected from these classes. Then, we'll fix it to ensure that the principle is respected.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> Area { <span class="hljs-keyword">get</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; Width * Height;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> : <span class="hljs-title">Rectangle</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Width
 {
   <span class="hljs-keyword">get</span> =&gt; <span class="hljs-keyword">base</span>.Width;
   <span class="hljs-keyword">set</span> =&gt; <span class="hljs-keyword">base</span>.Width = <span class="hljs-keyword">base</span>.Height = <span class="hljs-keyword">value</span>;
 }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Height
 {
   <span class="hljs-keyword">get</span> =&gt; <span class="hljs-keyword">base</span>.Height;
   <span class="hljs-keyword">set</span> =&gt; <span class="hljs-keyword">base</span>.Height = <span class="hljs-keyword">base</span>.Width = <span class="hljs-keyword">value</span>;
 }
}
</code></pre>
<p>Now, let’s test out if <code>Rectangle</code> calculates its area correctly:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

<span class="hljs-keyword">var</span> rect = <span class="hljs-keyword">new</span> Rectangle();
rect.Height = <span class="hljs-number">10</span>;
rect.Width = <span class="hljs-number">5</span>;

System.Console.WriteLine(<span class="hljs-string">"Expected area = 10 * 5 = 50."</span>);

System.Console.WriteLine(<span class="hljs-string">"Calculated area = "</span> + rect.Area);
</code></pre>
<p>Running the program:</p>
<pre><code class="lang-plaintext">Expected area = 10 * 5 = 50.

Calculated area = 50
</code></pre>
<p>Perfect!</p>
<p>Now, in our program, the <code>Square</code> class inherits from, or extends, the <code>Rectangle</code> class, because, mathematically, a square is just a special type of rectangle, where its height equals its width. Because of this, we decided that <code>Square</code> should extend <code>Rectangle</code> – it’s like saying “a square <em>is a</em> (special type of) rectangle”.</p>
<p>But look what happens if we substitute the <code>Rectangle</code> class for the <code>Square</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> rect = <span class="hljs-keyword">new</span> Square();
rect.Height = <span class="hljs-number">10</span>;
rect.Width = <span class="hljs-number">5</span>;

System.Console.WriteLine(<span class="hljs-string">"Expected area = 10 * 5 = 50."</span>);

System.Console.WriteLine(<span class="hljs-string">"Calculated area = "</span> + rect.Area);
</code></pre>
<pre><code class="lang-plaintext">Expected area = 10 * 5 = 50.

Calculated area = 25
</code></pre>
<p>Oh dear, LSP has been violated: we replaced the object of a superclass (<code>Rectangle</code>) with an object of its subclass (<code>Square</code>), and it affected the correctness of our program. By modeling <code>Square</code> as a subclass of <code>Rectangle</code>, and allowing width and height to be independently set, we violate the LSP. When setting the width and height of a <code>Square</code>, it should retain its squareness, but our implementation allows for inconsistency.</p>
<p>Let’s fix this to satisfy LSP:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> Area { <span class="hljs-keyword">get</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; Width * Height;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> sideLength;

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> SideLength
 {
   <span class="hljs-keyword">get</span> =&gt; sideLength;
   <span class="hljs-keyword">set</span>
   {
     sideLength = <span class="hljs-keyword">value</span>;
   }
 }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; sideLength * sideLength;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

Shape rectangle = <span class="hljs-keyword">new</span> Rectangle { Width = <span class="hljs-number">5</span>, Height = <span class="hljs-number">4</span> };

Console.WriteLine(<span class="hljs-string">$"Area of the rectangle: <span class="hljs-subst">{rectangle.Area}</span>"</span>);

Shape square = <span class="hljs-keyword">new</span> Square { SideLength = <span class="hljs-number">5</span> };

Console.WriteLine(<span class="hljs-string">$"Area of the square: <span class="hljs-subst">{square.Area}</span>"</span>);
</code></pre>
<p>In this corrected example, we redesign the <code>Square</code> class to directly set the side length. Now, a <code>Square</code> is correctly modeled as a subclass of <code>Shape</code>, and it adheres to the Liskov Substitution Principle.</p>
<p>How does this satisfy LSP? Well, we have a superclass, <code>Shape</code>, and subclasses <code>Rectangle</code> and <code>Square</code>. Both <code>Rectangle</code> and <code>Square</code> maintain the correct expected behavior of a <code>Shape</code> — we can substitute a square for a rectangle and the area will still be calculated correctly.</p>
<h2 id="heading-interface-segregation-principle-isp-in-c">Interface Segregation Principle (ISP) in C</h2>
<blockquote>
<p>Clients should not be forced to depend on interfaces they do not use.</p>
</blockquote>
<p>This principle encourages the creation of fine-grained interfaces that contain only the methods required by the clients that use them. It helps to prevent the creation of "fat" interfaces that force clients to implement unnecessary methods, leading to cleaner and more maintainable code.</p>
<p>Let's consider an example involving 2D and 3D shapes, initially violating the ISP.</p>
<p><strong>Violating ISP:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>; <span class="hljs-comment">// problem: 2D shapes don't have volume!</span>
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">IShape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Volume not applicable for 2D shapes."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sphere</span> : <span class="hljs-title">IShape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> * Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> (<span class="hljs-number">4.0</span> / <span class="hljs-number">3.0</span>) * Math.PI * Math.Pow(Radius, <span class="hljs-number">3</span>);
 }
}
</code></pre>
<p>In this example, we have an <code>IShape</code> interface representing both 2D and 3D shapes. However, the <code>Volume()</code> method is problematic for 2D shapes, like <code>Circle</code> and <code>Rectangle</code>, because they don't have volume. This violates the ISP because clients (classes using the <code>IShape</code> interface) may be forced to depend on methods they do not need.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> circle = <span class="hljs-keyword">new</span> Circle();
circle.Radius = <span class="hljs-number">10</span>;

System.Console.WriteLine(circle.Area());
System.Console.WriteLine(circle.Volume()); <span class="hljs-comment">// My text editor doesn't flag a problem...</span>

<span class="hljs-keyword">var</span> sphere = <span class="hljs-keyword">new</span> Sphere();
sphere.Radius = <span class="hljs-number">10</span>;

System.Console.WriteLine(sphere.Area());
System.Console.WriteLine(sphere.Volume());
</code></pre>
<p>Usually, if I try to call a method on an object that doesn’t exist, VS Code will tell me that I’m making a mistake. But above, when I call <code>circle.Volume()</code>, VS code is like “no problem”. And VS code is correct, because the <code>IShape</code> interface forces <code>Circle</code> to implement a <code>Volume()</code> method, even though circles don’t have volume.</p>
<p>It’s easy to see how violating ISP can introduce bugs into a program – above, everything looks fine, until we run the program and an exception gets thrown.</p>
<p><strong>Fixing ISP</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape2D</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape3D</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">IShape2D</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sphere</span> : <span class="hljs-title">IShape3D</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> * Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> (<span class="hljs-number">4.0</span> / <span class="hljs-number">3.0</span>) * Math.PI * Math.Pow(Radius, <span class="hljs-number">3</span>);
 }
}
</code></pre>
<p>In the fixed example, we've <em>segregated</em> the <code>IShape</code> interface into two smaller, more focused interfaces: <code>IShape2D</code> and <code>IShape3D</code>. Each shape class now implements only the interface that is relevant to its functionality.</p>
<p>This adheres to the Interface Segregation Principle by ensuring that clients are not forced to depend on methods that they do not use. Clients can now depend only on the interfaces that they need, promoting better code reuse and flexibility.</p>
<p>Next up, the fifth and final SOLID principle…</p>
<h2 id="heading-dependency-inversion-principle-dip-in-c">Dependency Inversion Principle (DIP) in C</h2>
<blockquote>
<p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p>
</blockquote>
<p>Dependency Inversion is the strategy of depending upon interfaces or abstract classes rather than upon concrete classes. This principle promotes decoupling between modules and promotes the use of interfaces or abstract classes to define dependencies, allowing for more flexible and testable code.</p>
<p>Let's start with an example violating the DIP and then we’ll correct it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span> <span class="hljs-comment">// Engine is our "low-level" module</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>
 {
   System.Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-comment">// Car is our "high-level" module</span>
{
 <span class="hljs-keyword">private</span> Engine engine;

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">this</span>.engine = <span class="hljs-keyword">new</span> Engine(); <span class="hljs-comment">// Direct dependency on concrete Engine class</span>
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
 {
   engine.Start();
   System.Console.WriteLine(<span class="hljs-string">"Car started."</span>);
 }
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>Car</code> class directly creates an instance of the <code>Engine</code> class, leading to a tight coupling between Car and Engine.</p>
</li>
<li><p>If the <code>Engine</code> class changes, it may affect the <code>Car</code> class, violating the Dependency Inversion Principle.</p>
</li>
</ul>
<p>The UML diagram below shows that <code>Car</code> depends on <code>Engine</code>:</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdbd6IZ4TfDmGCPIjsJJHTtEw7_WBxCP-H1cSme78Ze7qJq0fG6tQzNo7A-IbgnnruAZwMBhjuJoozA0rzA9RM35Pu9vWpk4I2Hp6Szk7Ns_kTFbu2oIIfHQa9ceBembsjN8EUlZLkQuB863NyzeeSn7qY?key=p75tPpeumlH4kqsSJuxz6w" alt="AD_4nXdbd6IZ4TfDmGCPIjsJJHTtEw7_WBxCP-H1cSme78Ze7qJq0fG6tQzNo7A-IbgnnruAZwMBhjuJoozA0rzA9RM35Pu9vWpk4I2Hp6Szk7Ns_kTFbu2oIIfHQa9ceBembsjN8EUlZLkQuB863NyzeeSn7qY?key=p75tPpeumlH4kqsSJuxz6w" width="728" height="728" loading="lazy"></p>
<p>But what do we mean by “high level” and “low level” classes?</p>
<p><strong>High-Level Class</strong>: The high-level class is typically the one that represents the main functionality or business logic of the application. It orchestrates the interaction between various components and is often more abstract in nature.</p>
<p>In this example, the <code>Car</code> class can be considered the high-level class. It represents the main functionality related to starting the car and driving it. The <code>Car</code> class is concerned with the overall behavior of the car, such as controlling its movement.</p>
<p><strong>Low-Level Class</strong>: The low-level class is usually one that provides specific functionality or services that are used by the high-level class. It typically deals with implementation details and is more concrete in nature.</p>
<p>In this example, the <code>Engine</code> class can be considered the low-level class. It provides the specific functionality related to starting the engine. The <code>Engine</code> class encapsulates the details of how the engine operates, such as ignition and combustion.</p>
<p>So in summary, the <code>Car</code> class is the high-level class, representing the main functionality of the application related to the car's behavior.</p>
<p>The <code>Engine</code> class is the low-level class, providing specific functionality related to the operation of the engine, which is used by the Car class.</p>
<p><strong>Fixing DIP:</strong></p>
<p>To adhere to the Dependency Inversion Principle, we introduce an abstraction (interface) between <code>Car</code> and <code>Engine</code>, allowing <code>Car</code> to depend on an abstraction instead of a concrete implementation.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IEngine</span>
{
 <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span> : <span class="hljs-title">IEngine</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>
 {
   System.Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>
{
 <span class="hljs-keyword">private</span> IEngine engine;

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params">IEngine engine</span>)</span>
 {
   <span class="hljs-keyword">this</span>.engine = engine;
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
 {
   engine.Start();
   System.Console.WriteLine(<span class="hljs-string">"Car started."</span>);
 }
}
</code></pre>
<p>We can now <em>inject</em> any type of engine into <code>Car</code> implementations:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> engine = <span class="hljs-keyword">new</span> Engine(); <span class="hljs-comment">// concrete implementation to be "injected" into the car</span>

<span class="hljs-keyword">var</span> car = <span class="hljs-keyword">new</span> Car(engine);

car.StartCar();
</code></pre>
<p>From the UML diagram below, we can see that both objects now depend on the abstraction level of the interface. <code>Engine</code> has inverted its dependency on <code>Car</code>.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf2Wes5g5HoeLNGoo4weo-gO6AVdVJ1WbRZxUfTEXIFROup8qCeUiQ8l5CsrwXkC5I1_0i3Q5DyzN5wpXSgjol2_RNFysFKpjMyj4SdEI2lFOplOs-uCUxZGEWE9fI4sFzMKfQOvOx33HKViFcXoqTVmi2s2FcLvCobCCZAvA?key=hfr-bV5v9p97pXexBFuY1A" alt="AD_4nXf2Wes5g5HoeLNGoo4weo-gO6AVdVJ1WbRZxUfTEXIFROup8qCeUiQ8l5CsrwXkC5I1_0i3Q5DyzN5wpXSgjol2_RNFysFKpjMyj4SdEI2lFOplOs-uCUxZGEWE9fI4sFzMKfQOvOx33HKViFcXoqTVmi2s2FcLvCobCCZAvA?key=hfr-bV5v9p97pXexBFuY1A" width="564" height="1248" loading="lazy"></p>
<p>In this corrected example:</p>
<ol>
<li><p>We define an interface <code>IEngine</code> representing the behavior of an engine.</p>
</li>
<li><p>The <code>Engine</code> class implements the <code>IEngine</code> interface.</p>
</li>
<li><p>The <code>Car</code> class now depends on the <code>IEngine</code> interface instead of the concrete <code>Engine</code> class.</p>
</li>
<li><p>Dependency injection is used to inject the <code>IEngine</code> implementation into the <code>Car</code> class, promoting loose coupling. Now, if we want to give a car a different type of engine, for example a <code>FastEngine</code>, we can inject that in instead. </p>
</li>
<li><p>Now, if the implementation of the engine changes, it won't affect the <code>Car</code> class as long as it adheres to the <code>IEngine</code> interface.</p>
</li>
</ol>
<p>Dependency Injection (DI) offers several advantages in software development:</p>
<ul>
<li><p><strong>Decoupling</strong>: DI promotes loose coupling between components by removing direct dependencies. Components rely on abstractions rather than concrete implementations, making them more independent and easier to maintain.</p>
</li>
<li><p><strong>Testability</strong>: Dependency injection simplifies unit testing by allowing components to be easily replaced with mock or stub implementations during testing. This enables isolated testing of individual components without relying on their dependencies.</p>
</li>
<li><p><strong>Flexibility</strong>: DI provides flexibility in configuring and swapping dependencies at runtime. It allows different implementations of dependencies to be used interchangeably without modifying the client code, facilitating runtime customization and extensibility.</p>
</li>
<li><p><strong>Readability and Maintainability</strong>: By explicitly specifying dependencies in the constructor or method parameters, DI improves code readability and makes the codebase easier to understand. It also reduces the risk of hidden dependencies, leading to more maintainable and understandable code.</p>
</li>
<li><p><strong>Reusability</strong>: DI promotes component reusability by decoupling them from their specific contexts or environments. Components can be designed to be independent of the application framework or platform, making them more portable and reusable in different projects or scenarios.</p>
</li>
<li><p><strong>Scalability</strong>: DI simplifies the management of dependencies in large-scale applications by providing a standardised approach for dependency resolution. It helps prevent dependency hell and makes it easier to manage and scale complex systems.</p>
</li>
</ul>
<p>Overall, dependency injection enhances modularity, testability, and maintainability of software systems, contributing to improved software quality and developer productivity.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations – you now understand the extremely important SOLID principles. These principles are going to save you a lot of headaches during your software development career, and guide you towards creating beautiful, maintainable, flexible, testable software.</p>
<p>If you’d like to take your software development skills to the next level and learn:</p>
<ul>
<li><p>OOP principles: encapsulation, abstraction, inheritance, polymorphism, coupling, composition, composition vs inheritance, fragile base class problem.</p>
</li>
<li><p>All 23 design patterns (“The Gang of Four Design Patterns”) with real world examples.</p>
</li>
<li><p>Unified Modeling Language (UML): the standard way to model classes and the relationships between them.</p>
</li>
</ul>
<p>Then check out my book:</p>
<p><a target="_blank" href="https://www.amazon.com/Mastering-Design-Patterns-Beginner-Friendly-Principles/dp/B0DBZGQZMZ">Mastering Design Patterns in C#: A Beginner-Friendly Guide, Including OOP and SOLID Principles on Amazon</a> (also available on <a target="_blank" href="https://doabledanny.gumroad.com/l/ennyj">Gumroad</a>).</p>
<p>Hopefully this article helps you to become a better OOP software developer!</p>
<p>Thanks for reading,</p>
<p><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Danny</a> 😎</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
