Laszlo

Hello, I am Laszlo

Software-Engineer, .NET developer

Contact Me

Distinct and HashSet

A common pattern in business-as-usual (BAU) applications is that a class in the business logic layer requests a set of entities by their integer IDs from a repository class. Here is one possible implementation of this pattern:

  1. A method in the business layer receives a list of integers as an argument (List<int>).
  2. It applies filtering and selection on these integers by creating a new enumerable.
  3. It extracts the unique values from the filtered and projected numbers.
  4. It passes the filtered, selected unique numbers to a query method in the repository class.
  5. This repository method processes the passed in integer enumerable:
    • If there aren't any numbers in the enumeration, it returns null (or empty results).
    • Otherwise, it copies the numbers into an SQL query and returns the query's result.

In this blog post, I will focus on two possible implementations to produce the unique set of integers:

  1. Using the Distinct LINQ extension method.
  2. Using the ToHashSet<T> method to materialize the result before passing it to the repository class.

Find out more »


Extension Members in C# 14

In this post, I explore C# 14's extension members feature and how it is compiled into IL code.

From Extension Methods to Extension Members

Previous versions of C# allowed developers to declare extension methods. The code snippets in this post are for demonstration purposes only and should not be used directly in production applications:

string value = "ThisIsPascalCased";
Console.WriteLine(value.ToCamel());

public static class MyExtensions
{
    public static string ToCamel(this string str) => str.Length switch
    {
        0 => string.Empty,
        1 => str.ToLowerInvariant(),
        _ => new([char.ToLower(str[0]), .. str[1..]])
    };
}

Find out more »


Using ClrMD for string analysis

Analysis of a .NET application's memory dump often reveals that byte[] and string types are among the most commonly allocated objects. This is not surprising, as most UI and web applications use string types to display data to users or byte[]/string to pass data over the network in HTTP/2 requests and responses. These string objects commonly represent configuration values, string literals, or data allocated by dependent libraries.

Analyzing strings in such a noisy environment is challenging. While common tools like Visual Studio, PerfView, and dotnet-dump provide high-level analysis, drilling into the details is often difficult. ClrMD is one of the tools that enables programmatic analysis of memory dumps. In my previous post Getting Started with ClrMD, I introduced how to analyze a full memory dump of a .NET application. This post explores a specialized analysis for strings: identifying application-defined types that hold references to large strings. These are the strings that developers have direct control over in their application code.

Execution Steps

First, collect a memory dump of a running application:

Find out more »


Object Stack Allocation in .NET 10

Object Stack Allocation is a performance optimization feature in .NET 10 that allows certain objects to be allocated on the stack instead of the heap. The JIT compiler identifies objects and object allocations that don't escape from a method and may decide to allocate these non-escaping objects on the stack. When these objects are stack-allocated, they get freed automatically when the stack frame is freed as the method returns, reducing the load on the Garbage Collector (GC).

Recent improvements in this area have been detailed in the Performance Improvements in .NET 10 blog post.

In this post, I will investigate the current state and limitations of this feature. Please note that the findings reveal some of the current internal limitations of the runtime, which may change or be adjusted in future releases.

Using Stopwatch

Find out more »


SIMD Sum 2

In this post, I'll explore how to optimize a simple array summing operation using SIMD (Single Instruction Multiple Data) operations in C#. The example is inspired by Matt Godbolt's GOTO 2024 talk What Every Programmer Should Know about How CPUs Work - Matt Godbolt - GOTO 2024 about CPU architecture and branch prediction. We'll see how leveraging SIMD instructions can dramatically improve performance by reducing branch mispredictions and processing multiple elements in parallel.

A part of this talk describes the branch prediction feature of CPU. It uses a simple task for demonstration: a method is given a large set of random numbers, sums the total of the numbers and separately also sums the numbers below 128. The talk shows a sample implementation in Python and C++ and explains the reasons for the observed performance difference.

In this post I will implement this example in C# with a single difference: the set of input numbers are bytes and not ints.

Naive Implementation

Find out more »