0% found this document useful (0 votes)
49 views

Cheat Sheet: Records

Records are a new immutable type in C# that can simplify code by removing the need to create classes for simple, immutable data structures. Records support both structural equality, which compares the structure of the records, and referential equality, which compares the references. Mutable records can also be created by adding setters to the record properties. Pattern matching was enhanced in C# 9 with additional pattern types like type, combinator, parenthesized, and relational patterns to provide more powerful matching capabilities.

Uploaded by

erick caba
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views

Cheat Sheet: Records

Records are a new immutable type in C# that can simplify code by removing the need to create classes for simple, immutable data structures. Records support both structural equality, which compares the structure of the records, and referential equality, which compares the references. Mutable records can also be created by adding setters to the record properties. Pattern matching was enhanced in C# 9 with additional pattern types like type, combinator, parenthesized, and relational patterns to provide more powerful matching capabilities.

Uploaded by

erick caba
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

Records

A new C# type that is immutable by default. The equality between Records is compared by
structure or by reference.

// Default Record.
public record Person(string Name, int Age);

// Mutable Record.
public record Person(string Name, int Age)
{
public string Name { get; set; } = Name;
public int Age { get; set; } = Age;
}
var person1 = new Person("Bassam Alugili",42 );
var person2 = new Person("Bassam Alugili",42);

Console.WriteLine(person1 == person2); // True; Structural equality.


Console.WriteLine(person1.Equals(person2)); // True; Structural equality.

// False; Referential equality.

Cheat Sheet
Console.WriteLine(ReferenceEquals(person1, person2));

var person3 = person1 with { Age = 43 }; // Change the default record! -->
Create a new one!
Console.WriteLine(person1 == person3); // False; Structural equality.

// Change the mutable record.


person1.Age = 43;
var (name, age) = person3; // Destruct a record.
https://github.com/alugili Pros:
Records are a lightweight type that can remove a lot of code.
Structural equality and Referential equality.

28.11.2020 Cons:
Allocating a lot of objects.
Pattern Matching Enhancements
C# 9 contains six main changes in pattern matching. Type patterns enhancements and all other patterns are introduced in C# 9.

Type patterns is used to match the input against a type. If the input type is a match to the type specified in the pattern, the match succeeds. C# 9 removes the type pattern followed by
another pattern restriction.
Combinator Patterns Permit the programmer to combine multiple patterns on one line with AND/OR operators or to negate a pattern by using the NOT operator.
- Conjunctive patterns represent the logical “and” of the two sub-patterns pattern1 and pattern2.
- Disjunctive patterns represent the logical “or” of the two sub-patterns pattern1 and pattern2.
- Negated “not” pattern that requires a given pattern not to match.
Parenthesized patterns permit the programmer to put parentheses around any pattern.
Relational patterns permit the programmer to match their input against constant values to determine if the input is > or < or = to that constant.

Type Patterns And patterns Parenthesized patterns


object checkType = new int(); var person = new Person("Bassam", 43); public record IsNumber(bool Isvalid, int Number);
var getType = checkType switch var is10 = new IsNumber(true, 10);
{ var ageInRange = person switch var n10 = is10 switch
string => "string", // match against the type only. { {
int => "int", Person(_, < 18) => "less than 18", ((_,>1 and <5) and (_,>5 and <9)) or (_,10) => "10",
_ => "obj" ("Bassam",_) and (_,>18)=>"Bassam is greater than 18" _=> "not 10"
}; }; };
Console.WriteLine(n10); // Output: 10
Console.WriteLine(getType); // Output: int // Output: Bassam is greater than 18
Console.WriteLine(ageInRange); Relational Patterns
Or patterns var person = new Person("Bassam", 43);
var person = new Person("Bassam", 43); Negated not patterns var person2 = new Person("Thomas", 4);
var ageInRange = person switch var person = new Person("Bassam", 43); var ageInRange = person switch
{ var meOrNot = person switch {
Person(_, < 18) => "less than 18", { Person(_, < 18) => "less than 18",
(_, 18) or (_, > 18) => "18 or greater" not ("Bassam", 43) => "not me!", (_, > 18) => "greater than 18",
}; _=>"Me :-)" (_, 18) => "18 years old!"
// Output: 18 or greater. }; };
Console.WriteLine(ageInRange); // Output: greater than 18
Console.WriteLine(meOrNot); Console.WriteLine(ageInRange);
Native Ints Init Only Setters Localsinit
C# 9 adds two new data types (nint, nuint). The new types are This feature allows you to create an object in the nominal code In C# 9, you can use the new attribute
depending on the host platform and the compilation settings style. Object initializer belongs to the nominal category. SkipLocalsInit to instruct the compiler to
suppress the emitting .locals init flag. This
nint nativeInt = 55; public class InitDemo attribute applies at module, class, or method
Console.WriteLine(nint.MaxValue); { level.
public string Start { get; init; }
Compiled in x86 Configuration public string Stop { get; init; } [System.Runtime.CompilerServices.SkipLocalsInit]
static unsafe void DemoLocalsinit()
Output: 2147483647 }
{
// Creating the object with the nominal style. int x;
Compiled in x64 Configuration var initDemo = new InitDemo
Output: 9223372036854775807 { // Take care! x is not initialized!
Start = "S1", Console.WriteLine(*&x);
}
Pros: Stop = "S2"
Make C# more compatible with Mac and iOS APIs. };
Pros:
Improves the performance of the methods.
Cons: Pros:
A lot of C# developers are not familiar with this concept. Nice syntax and it removes some code overhead.
Cons:
The impact on the method performance in most
Target New Types Target-typed Conditional Expressions cases is small. Please use it only if you know
exactly what you are doing! And with profiling.
This feature allows you to omit the type of object you are This feature allows you the implicit conversion from the null
instantiating. coalescing expression.
Point p = new(1, 1);
ConcurrentDictionary<int, int> dict = new();
Point[] ps = {new(1, 1),new(2, 2),new(3, 3)}; void M(int[] list, uint? u)
{
Pros: int[] x = list ?? (int[]) new[] {1,2};
Less code. var l = u ?? -1; // C# 9 in C# 8 you need -1u
}
Cons:
It can make your code harder to read.
Extension GetEnumerator
This feature allows you to create an extension method to allow foreach loops on IEnumerator<T> and IAsyncEnumerator<T> interfaces.

public static class Extensions


{
public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> enumerator) => enumerator;
}

With the above extension you can do:

IEnumerator<string> enumerator = new Collection<string> { "Bassam", "Thomas", "Volker" }.GetEnumerator();

foreach (var guru in enumerator)


{
Console.WriteLine($"Welcome {guru}!");
}

Lambda Discard Parameters Attributes on Local Functions Extending Partial Methods


This feature allows you to add multiple discards (_,_) to The idea is to permit attributes to be part of the This feature allows you to remove the partial method's
be used as ignored parameters of lambdas and declaration of a local function. restrictions (void, out, accessibility).
anonymous methods.
static void Main(string[] args) partial class Doing
{ {
Func<int,int,int> zero = (_,_) => 0; [Conditional("DEBUG")] internal partial bool DoSomething(string s, out int i);
// NotNull-attribute. }
Pros: static void DoSomething([NotNull] string test)
Syntax Sugar. { partial class Doing
Console.WriteLine("Do it!"); {
} internal partial bool DoSomething(string s, out int i)
{
i = 0;
DoSomething (“Doing!"); return true;
} }
}
Static Anonymous Functions Covariant Return Types About me
This feature allows you to use the static keyword for lambdas Covariant return types is a feature in which a subclass of a type
to prevent capturing locals and parameters. can be specified in a method override in a derived type; in
other words, the overridden method has a more specific
public int number = 5; return type than the declaration in the base type.
….
Func<string> toString = () => number.ToString();
Console.WriteLine(toString()); public virtual Person GetPerson()
{
// This is the parent (or base) class.
The field number is captured by the anonymous lambda
return new Person();
function and can cause an unintended allocation. To solve that
}
you can add the modifier static on the lambda and use the
const modifier on the field (number). public override Person GetPerson()
{
public const int number = 5; //You can return the child class, but still return a Person
…. return new Student();
Func<string> toString =static () => number.ToString(); }
Console.WriteLine(toString());
Now, you can return the more specific type in C# 9.
Pros:
Anonymous methods need allocations, and this feature might public virtual Person GetPerson()
help to make it more performant. {
// This is the parent (or base) class.
Module Initializers return new Person(); Bassam Alugili
}
The module initializer code is executed when an assembly is Senior Software Specialist/Database
Loaded/ Initialized. You can compare it with the static public override Student GetPerson() Expert at STRATEC SE
constructor in C#, but in the case of module initializers, the { [email protected]
method is executed only once for the entire assembly. // Better! https://github.com/alugili
return new Student(); www.bassam.ml
[ModuleInitializer] }
public static void DoSomethingBeforeMain()
{
Pros:
Console.WriteLine(“Huhu”);
It can help you to remove a lot of ugly typecasting.
}

You might also like