Overview
With C# 9, developers will be able to write and manage code more efficiently with powerful features - records and enhanced pattern matching. The purpose of this article is to demonstrate how C# 9 records and pattern matching contribute to writing concise and readable code, by understanding their capabilities and demonstrating how they work together.
C# 9 Records: Simplicity in Data Structures
Immutable by Default
The compiler automatically generates an immutable class when you define a record in C# 9, which reduces boilerplate code.
In the code example below we have a Person record defined with two properties (FirstName and LastName). The compiler generates a class with these properties, making Person instances immutable.
using System.Collections;
namespace CSharp9RecordPatternMatchingExamples;
public class Data
{
//Immutable by Default example
public record Person(string FirstName, string LastName);
}
Value Equality
As a result, records implement value equality, comparing the values of their properties instead of references. This simplifies the code and makes it easier to read.
The code example below is in this case, the value equality check returns true since the property values are the same for both instances.
//Value Equality
var person1 = new Person("John", "Doe");
var person2 = new Person("John", "Doe");
if (person1 == person2)
{
Console.WriteLine("Both persons are equal.");
}
Deconstruction
In addition to supporting deconstruction, records allow easy extraction of property values.
As shown in the code example below, the FirstName and LastName properties are separated into separate variables.
//Deconstruction
var person = new Person("Jane", "Doe");
var (firstName, lastName) = person;
Console.WriteLine($"First Name: {firstName}, Last Name: {lastName}");
Pattern Matching: Enhancing Control Flow
Type Patterns
As a result of pattern matching, type checking, and casting are simplified, enhancing control flow constructs.
In the example code below, a switch statement is used to determine the type of object and display a corresponding message.
using System.Collections;
namespace CSharp9RecordPatternMatchingExamples;
public class Data
{
//Type Patterns
public static string GetDisplayText(object obj)
{
return obj switch
{
string text => $"String: {text}",
int number => $"Number: {number}",
DateTime dateTime => $"Date and Time: {dateTime}",
double floatingPoint => $"Floating Point Number: {floatingPoint}",
bool boolean => $"Boolean: {boolean}",
IEnumerable enumerable => $"Enumerable: {string.Join(", ", enumerable.Cast<object>())}",
_ => "Unknown"
};
}
}
//Type Patterns
string strExample = "I am Ziggy Rafiq!";
int intExample = 32;
DateTime dateTimeExample = DateTime.Now;
double doubleExample = 3.14;
bool boolExample = true;
Console.WriteLine(GetDisplayText(strExample));
Console.WriteLine(GetDisplayText(intExample));
Console.WriteLine(GetDisplayText(dateTimeExample));
Console.WriteLine(GetDisplayText(doubleExample));
Console.WriteLine(GetDisplayText(boolExample));
Property Patterns
The pattern matching extends to properties, making code more expressive and concise.
In the code example below, the switch statement identifies shapes based on their width and height.
//Model
namespace CSharp9RecordPatternMatchingExamples.PatternMatching.Models
{
public class Shape
{
public int Width { get; set; }
public int Height { get; set; }
}
}
//Static String Method/Function
using CSharp9RecordPatternMatchingExamples.PatternMatching.Models;
namespace CSharp9RecordPatternMatchingExamples.PatternMatching
{
public static class ShapeInfo
{
public static string GetShapeDescription(object shape)
{
return shape switch
{
Shape { Width: 0, Height: 0 } => "Point",
Shape { Width: var w, Height: var h } when w == h => $"Square with side {w}",
Shape { Width: var w, Height: var h } => $"Rectangle with width {w} and height {h}",
_ => "Unknown Shape"
};
}
}
}
//Property Patterns
// Example 1: Point
Shape point = new Shape { Width = 0, Height = 0 };
Console.WriteLine(ShapeInfo.GetShapeDescription(point)); // Output: Point
// Example 2: Square
Shape square = new Shape { Width = 5, Height = 5 };
Console.WriteLine(ShapeInfo.GetShapeDescription(square)); // Output: Square with side 5
// Example 3: Rectangle
Shape rectangle = new Shape { Width = 3, Height = 7 };
Console.WriteLine(ShapeInfo.GetShapeDescription(rectangle)); // Output: Rectangle with width 3 and height 7
// Example 4: Unknown Shape
Shape unknownShape = new Shape { Width = 2, Height = 4 };
Console.WriteLine(ShapeInfo.GetShapeDescription(unknownShape)); // Output: Unknown Shape
Summary
C# 9 records and pattern matching enhance the expressiveness and simplicity of code. Records simplify the creation of immutable data structures, while pattern matching enhances control flow constructs. By leveraging these features, developers can create code that is more concise, readable, and maintainable.
Take advantage of the power of records and pattern matching as you explore C# 9. These features can simplify complex tasks, improve code clarity, and elevate your overall development experience.
Please do not forget to like this article if you have found it useful and follow me on my LinkedIn https://www.linkedin.com/in/ziggyrafiq/ also I have uploaded the source code for this article on my GitHub Repo https://github.com/ziggyrafiq/CSharp9RecordPatternMatchingExamples