Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
46 views5 pages

CSharp 9 CheatSheet.

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
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.
Cheat Sheet
// False; Referential equality.
Console.WriteLine(ReferenceEquals(person1, person2));
https://github.com/alugili
// Change the default record! --> Create a new one! 28.11.2020
var person3 = person1 with { Age = 43 };

Console.WriteLine(person1 == person3); // False; Structural equality.


var (name, age) = person3; // Destruct a record.
Pros:
// Change the Mutable Record.
Records are a lightweight type that can remove a lot of code.
person1.Age = 43;
Structural equality and Referential equality.
Inheritance:
public record PersonInheritance(string Name, int Age, string Country):Person(Name, Age); Cons:
var personInherited = new PersonInheritance("Bassam Alugili", 42, "Germany"); Allocating a lot of objects.

Console.WriteLine(person1 == personInherited); // False; Type check! not equal.


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: Me ☺ // 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 Function Pointers
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 This feature allows you to use delegate* for the
other words, the overridden method has a more specific declaration of function pointers.
public int number = 5; return type than the declaration in the base type.
…. unsafe class FunctionPointer
Func<string> toString = () => number.ToString(); {
Console.WriteLine(toString()); public virtual Person GetPerson() static int GetLength(string s) => s.Length;
{
// This is the parent (or base) class. delegate*<string, int> functionPointer =
The field number is captured by the anonymous lambda &GetLength;
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 public void Test()
{
const modifier on the field (number). public override Person GetPerson() // Output: 4
{ Console.WriteLine(functionPointer("test"));
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. { About me
// This is the parent (or base) class.
Module Initializers return new Person();
}
The module initializer code is executed when an assembly is
Bassam Alugili
Loaded/ Initialized. You can compare it with the static public override Student GetPerson() Senior Specialist/Database
constructor in C#, but in the case of module initializers, the { Expert at STRATEC SE
method is executed only once for the entire assembly. // Better! alugili@gmail.com
return new Student(); https://github.com/alugili
[ModuleInitializer] }
public static void DoSomethingBeforeMain() www.bassam.ml
{
Pros:
Console.WriteLine(“Huhu”);
It can help you to remove a lot of ugly typecasting.
}

You might also like