8 🍨 Sweet Treats 🍨 in Modern C#
Tags: csharp, dotnet
Published: 2022-03-14 07:07:50

# C# through the Ages

![alt text](https://media1.giphy.com/media/mpTN9Ogfp4gWA/giphy.gif?cid=ecf05e47q527dy63obpngu861c4kk84sa9a76d6i4997ey1c&rid=giphy.gif&ct=g)

Many, many eons ago :sparkles:, C# 'twas but an archaic, _OOP focused_ language. Alas, 'tis no more! Many updates and feature requests later C# has evolved, shedding the _object focused_ shackles of its past, becoming a modern, **functional**, programming language. 

Here are 8 :fire: **sizzling** :fire: features to use from C# 7, 8, 9, and 10 to write modern C#.

# Throw Expressions

![throw simba](https://media0.giphy.com/media/koUtwnvA3TY7C/giphy.gif?cid=ecf05e47py7kp36artas731pdg6j54nmg75ga8qnw6g5d4yq&rid=giphy.gif&ct=g)

A simple lil' nugget :gem: that is most useful in constructors, when combined with the [null-coalescing operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator) is the **throw expression**

```csharp
public string Color { get; set; }
public int Size { get; set; }

// ctor
public Car(string? color, int? size)
{
    Color = color ?? throw ArgumentNullException(nameof(color));
    Size = size ?? throw ArgumentNullException(nameof(size));
}
```

If either `color` or `size` is null, the application will throw a `ArugmentNullException`.

Another useful place to use this is in conjunction with the [ternary operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator).

```csharp
public void SetCharacterLimitedName(string newName, int characterLimit)
{
    Name = newName.Length > characterLimit
        ? throw new ArgumentOutOfRangeException(nameof(newName))
        : newName;
} 
```
The method will throw an `ArgumentOutOfRangeException` if the length of the new name exceeds the character limit.

# Out Variables

Functions with `out` parameters, returning `boolean` values, make the best use of this feature. It allows us to do a conditional check, and if it passes we know something about the `out` variable, and can then use the variable within the scope of the check.

## Old way
```csharp
bool isLucky(int someNumber, out string result)
{
    // the number 7 is lucky
    result = someNumber == 7 ? "you win!" : "you lose...";
    return someNumber == 7;
}

string luckyMessage;
var isLucky = isLucky(11, out luckyMessage);

if (isLucky)
    Console.WriteLine(luckyMessage);
```

## New way
```csharp
bool isLucky(int someNumber, out string result)
{
    // the number 7 is lucky
    result = someNumber == 7 ? "you win!" : "you lose...";
    return someNumber == 7;
}

if (isLucky(7, out var message))
    Console.WriteLine(message);
```

This is much more concise, and easy to read!

# Pattern Matching with `and`, `or`, and `not`

The `and`, `or`, and `not` keywords have been added to pattern matching in C# to further enrich the _pattern matching_ experience. It makes the code more readable in _English_, and allows for many combinations of boolean checks in a single line, ensuring there is much less code. With the addition of `and`, `or` and `not` pattern matching goes into overdrive.

```csharp
// Setup
public enum Color
{
    Red,
    Orange,
    Green,
    Yellow
}

public class Fruit
{
    public string? Name { get; set; }
    public Color Color { get; set; }
    public bool IsTasty { get; set; }
    public int Quantity { get; set; }
}

// Implementation
var firstFruit = new Fruit
{
    Name = "Tomato",
    Color = Color.Red,
    IsTasty = true,
    Quantity = 10
};

var secondFruit = new Fruit
{
    Name = "Banana",
    Color = Color.Green,
    IsTasty = false,
    Quantity = 12
};

var thirdFruit = new Fruit
{
    Name = "Orange",
    Color = Color.Orange,
    IsTasty = false,
    Quantity = 50
};

if (firstFruit is {Name:"Tomato", IsTasty:true, Quantity:>1}
or {Name:"Tomato", Color:Color.Red, Quantity:>10})
    Console.WriteLine("Tomato, at least one tasty or at least 10 red");
        
if (secondFruit is {Name:"Banana"} and {IsTasty:true}
and {Color:Color.Yellow} and {Quantity:>12})
    Console.WriteLine("Banana, tasty and yellow and at least 12");

if (thirdFruit is {Name:"Orange"} and not {IsTasty:true}
or not {Color:Color.Orange, Quantity:<5})
    Console.WriteLine("Orange, not tasty or orange and less than 5");
```

# Pattern Matching :ice_cream: and `out`

![patterns](https://media4.giphy.com/media/yKufRw0jxE1oRHdHDd/giphy.gif?cid=ecf05e47pc5601y2oata0wudfsfwf9i2ql90o1y5clwnj8bf&rid=giphy.gif&ct=g)

Combining the aforementioned `out` variables with pattern matching, gives a wonderfully short, readable result

```csharp
object numberObject = "12345";

if (numberObject is int number
|| (numberObject is string numberString 
    && int.TryParse(numberString, out number))
{
    Console.WriteLine($"It's a number alright! {number}");
}
```
Here we check if the object is an `int`, or a `string`. If it is a `string`, we then try and parse it. If it parses then we have the result `number` available to use within the `if` block.

![but wait](https://media4.giphy.com/media/9V1F9o1pBjsxFzHzBr/giphy.gif?cid=ecf05e47v31d0wu5l524580le16pypi2a5hzadra57d18ahn&rid=giphy.gif&ct=g)

Pattern matching also extends far beyond simple type checks. Properties can be matched too!

```csharp
public class Fighter 
{
    public string? Name { get; set; }
    public string? Style { get; set; }
    public int Strength { get; set; }
    public bool IsChampion { get; set; }
}

var fighter = new Fighter { ... };

if (fighter is {IsChampion:true})
    Console.WriteLine($"{fighter.Name} is a champ!");

if (fighter is {Style:"Karate", Strength:>9000) 
    Console.WriteLine($"{fighter.Name} is powerful!");
```

Doing property patterns in this way also has the added benefit of an implicit null check. The `{}` pattern matches with everything except `null`.

# Switch Expressions + Property Patterns :nail_care:

![crown](https://media0.giphy.com/media/Jp4dchTKX6BzGkZ5DL/giphy.gif?cid=ecf05e47xbjzenfkczwz547q1yq31qndqilw9rexz8gtvs13&rid=giphy.gif&ct=g)

The **greatest** :clap: the **best** :clap: the most **amazing** :clap: of the new features - Switch Expressions! :sunglasses:

Combined with property patterns they allow a whole host of conditional operations, in a few short lines of :ice_cube: crisp C#. 

## We got em basic :blossom:
```csharp
public string Alakazam(int magicNumber)
{
    return magicNumber switch
    {
        1 => "pow",
        2 => "magic!",
        3 => "behold...",
        // default case
        _ => "ummm, I got nothing..."
    }
}
```

## And extra spicy :hot_pepper: :hot_pepper: :hot_pepper:
```csharp
// The setup
public class Monster
{
    public string? Name { get; set; }
    public int? NumberOfTentacles { get; set; }
    public bool? IsScary { get; set; }
    public Power? Power { get; set; }
}

public class Power
{
    public int Level { get; set; }
    public string? Element { get; set; }
    public bool? DoesPierceArmour { get; set; }
}

// The execution!!!
var monster = new Monster
{
    Name = "Mildred",
    NumberOfTentacles = 23,
    IsScary = true,
    Power = new Power
    {
        Level = 3000,
        Element = "Fire",
        DoesPierceArmour = false
    }
};

var res = monster switch
{
    var m when monster.NumberOfTentacles > 100 =>
        $"Too many damn tentacles! {m.NumberOfTentacles}",
    { IsScary: true } => "Ahhhhhhh!",
    { Power.Element: "Fire"} => "Ooo hot! hot! hot!",
    { Power.DoesPierceArmour: false } => "I ain't afraid of you!",
    var m when monster.Power.Level > 3000 =>
        $"So much power! {m.Power}",
    _ => "ummm, I got nothing?"
};
```

Each of the case statements are so *declarative* that their meaning is implicit. Simply by _reading_ the code you already know what's being checked at each case. So much meaning is suddenly contained in so little code.

This is the true power of :star2: Switch Expressions :star2:.

# (Named) Tuples

Ah, the humble tuple :full_moon_with_face:. So short. So sweet. And so very useful. Tuples really shine in places where you need to return multiple values but don't want to create a new object/type to do so.

```csharp

public (string name, bool isReadyToParty) SomeThing() =>
("Gerry", true);

// Destructuring the tuple
var (name, isReadyToParty) = SomeThing();

Console.WriteLine($"Name: {name}, Ready to Party? {isReadyToParty}")

```
When using named tuples, where each property of the tuple has a _name_, it can then be deconstructed on invocation, as `var (name, isReadyToParty)`. This gives a clean way to return multiple variables **AND** extract them in the calling code.

# Records

![records](https://media0.giphy.com/media/l3vQY93bN54rXJTrO/giphy.gif?cid=ecf05e47jw8imz96obms5fk7pwcetiyn6iwhm9qm85wsbgd3&rid=giphy.gif&ct=g)

`record` types have the _potential_ to be amazing. They're supposed to represent immutable objects - but are only immutaable through the use of `init` only setters. The `init` only setters ensure that their properties cannot be set after initialization - and hence guarantees immutability. **BUT* `record` types are not currently immutable by default, and that makes me sad :panda_face:.

[Immutability](https://en.wikipedia.org/wiki/Immutable_object#:~:text=In%20object%2Doriented%20and%20functional,modified%20after%20it%20is%20created.) is on of the cornerstones of the functional programming paradigm.

```csharp
public record Person
{
    public string? Firstname { get; init; }
    public string? Lastname { get; init; }
};

var person = new Person { Firstname = "Sam" };

// this throws an error
person.Lastname = "Person";
```

Immutability prevents the following pattern

```csharp

public record Person
{
    public string? Fullname { get; set; }
    public int? Counter { get; set; }
    public bool? IsTrue { get; set; }
};

var person = new Person { Fullname = "Anna" };

person.Counter++;
person.Fullname += " Luisa";
person.IsTrue != person.IsTrue;

someOtherMethod(person);
andAnotherMethod(person);
yetAnother(person);

/*
 *
 * 20 lines of code
 * passing person around
 *
*/

person.Counter++;
person.Fullname += " Magdalena";
person.IsTrue != person.IsTrue;

/*
 *
 * 20 lines of code
 * passing person around
 *
*/

person.Counter++;
person.Fullname += " Susanna";
person.IsTrue != person.IsTrue;

```

What is the `Person` object's name? What is the value of `Counter`? Do we know if it was mutated inside one of the methods - or maybe not. What is the value of `IsTrue`? By making `Person` immutable we can only set this once, and prevent this sort of mess from forming, or compounding on a single object. It simplifies the logical flow through the code.

# Adios Amigos

![adios](https://media0.giphy.com/media/xT9KVgHIvt5YJXT7W0/giphy.gif?cid=ecf05e475u3gbrtk2m6h0unvj0hfxzshq0xk1cz4b1v0dg2k&rid=giphy.gif&ct=g)

The breadth and scope of the **Modern C#** programming language, with its wealth of new features :ringed_planet:, introduced over the last 4 years, may seem overwhelming at first :sweat_smile:. However, learning to use these features a few at a time is easy :beach_umbrella: - and will drastically increase the enjoyment derived from working with C#.