New Pluralsight Course Update: Working with Nulls in C#

A new version of my Working with Nulls in C# Pluralsight course was just released. This new version features updated demos in .NET 5 & C# 9 plus a brand new module has been added.

The course contains the following modules:

  • Working with Nullable Value Types and Strings
  • Accessing and Checking for Null Values
  • Eliminating Null Reference Exceptions with the Null Object Pattern
  • Understanding Nullable and Non-nullable Reference Types
  • Using Additional Attributes to Describe Nullability

From the course description: “Making use of an object when it is not supposed to be null can result in unexpected exceptions that can cause your program to crash. These unexpected null related errors may cause data loss or corruption, system downtime, and unhappy users. In this course, Working with Nulls in C#, you’ll gain the ability to reduce the likelihood of getting null related exceptions in production. First, you’ll explore which objects can be set to null and how to check for null values. Next, you’ll discover a design pattern to help eliminate null related exceptions. Finally, you’ll learn how to opt-in to the ability to create non-nullable reference types that enable the compiler to detect null-related problems before you even run your application. When you’re finished with this course, you’ll have the skills and knowledge of nulls in C# needed to reduce null related errors in your production code.”

You can start watching with a Pluralsight free trial.

SHARE:

ICYMI C# 9 New Features: Reduce Boilerplate Constructor Code with Init Only Property Setters

This is part of a series of articles on new features introduced in C# 9.

Prior to C# 9 if you wanted to create properties that can be set only when the object is created, you could make  the property setter private and use constructor arguments to set them:

class PaymentV1
{
    public Guid Id { get; private set; }
    public decimal Value { get; private set; }
    public string Notes { get; set; }
    public PaymentV1(Guid id, decimal value)
    {
        Id = id;
        Value = value;
    }
}

In the preceding code, the Id and Value properties can only be set when the object is created by supplying constructor parameters. Once the Payment has been created you can’t set the Id or Value properties from outside the object instance.

In the preceding code, we have to add the extra constructor code just to create the “externally immutable” properties (they can still be set from code inside the class).

C# 9 introduces the concept of init only setters. These allow you to create immutable properties without needing to write the extra constructor boilerplate code:

class PaymentV2
{
    public Guid Id { get; init; }
    public decimal Value { get; init; }
    public string Notes { get; set; }
}

Notice in the preceding code that the Id and Value properties now use the init keyword instead of the set keyword. Also notice that we no longer need to create a constructor.

To set these immutable properties you need to do so at the time of object construction/creation by using the existing C# property initialization syntax, for example:

var payment2 = new PaymentV2
{
    Id = Guid.NewGuid(),
    Value = 45.50m,
    Notes = "Initial send on Friday."
};

Once this code executes and the payment2 object is created, you will not be able to set Id or Value:

payment2.Id = Guid.NewGuid(); // ERROR - only settable in initializer
payment2.Value = 99.00m; // ERROR - only settable in initializer
payment2.Notes += " Second send on Sunday."; // OK

You can also set init only properties from the constructor of a derived type:

abstract class PaymentBase
{
    protected Guid Id { get; init; }
    protected decimal Value { get; init; }
}

class PaymentV3 : PaymentBase
{
    public string Notes { get; set; }

    public PaymentV3(Guid id, decimal value)
    {
        Id = id;
        Value = value;
    }
}

You could also use init only properties and set a default value if the property is not set at creation and also add validation logic:

class PaymentV4
{
    private readonly string _currencyCode = "USD";

    public string CurrencyCode
    {
        get
        {
            return _currencyCode;
        }

        init 
        {
            if (value is null)
            {
                throw new ArgumentNullException(nameof(CurrencyCode));
            }

            if (value.Length != 3)
            {
                throw new ArgumentOutOfRangeException(nameof(CurrencyCode), "Must be 3 long.");
            }

            // etc.
            _currencyCode = value;
        }
    }
}

With the preceding code, we could try the follow statements:

var payment4 = new PaymentV4(); // Default CurrencyCode of "USD"
var payment4 = new PaymentV4 { CurrencyCode = "AUD" };
var payment4 = new PaymentV4 { CurrencyCode = null }; // Exception
var payment4 = new PaymentV4 { CurrencyCode = "hello" }; // Exception

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

ICYMI C# 9 New Features: Adding foreach Support To Any Type

This is part of a series of articles on new features introduced in C# 9.

Prior to C# 9 you could add foreach support to a class by modifying the class and implementing the IEnumerable interface. With C# 9 you can add foreach support to an existing class without actually needing to modify that class.

As an example, suppose the following class exists in our codebase:

public class Choices
{
    public string FirstChoice { get; set; }
    public string SecondChoice { get; set; }
    public string ThirdChoice { get; set; }
    public string FourthChoice { get; set; }
    public string FifthChoice { get; set; }
}

Because the class is in our control we could add the ability to foreach through all the choices (FirstChoice, SecondChoice, etc.).

One way to do this would be to modify the Choices class and implement IEnumerable – we could also just create a method called GetEnumerator and then have it return a class which has a MoveNext and Current method:

public class ChoicesEnumerator
{
    public string[] _choices = new string[5];

    int position = -1;

    public ChoicesEnumerator(Choices choices)
    {
        // Additional null/validation/etc checking code omitted

        _choices[0] = choices.FirstChoice;
        _choices[1] = choices.SecondChoice;
        _choices[2] = choices.ThirdChoice;
        _choices[3] = choices.FourthChoice;
        _choices[4] = choices.FifthChoice;
    }

    public bool MoveNext()
    {
        position++;
        return position < _choices.Length;
    }

    public string Current
    {
        get
        {
            try
            {
                return _choices[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}

We could then modify the Choices class and add the GetEnumerator method:

public class Choices
{
    public string FirstChoice { get; set; }
    public string SecondChoice { get; set; }
    public string ThirdChoice { get; set; }
    public string FourthChoice { get; set; }
    public string FifthChoice { get; set; }
    
    public ChoicesEnumerator GetEnumerator()
    {
        return new ChoicesEnumerator(this);
    }
}

Now we can iterate through the choices in a foreach loop:

var choices = new Choices
{
    FirstChoice = "Orange",
    SecondChoice = "Blue",
    ThirdChoice = "Green",
    FourthChoice = "Cyan",
    FifthChoice = "Grey"
};

foreach (var choice in choices)
{
    WriteLine(choice);
}

But what if we were not able to modify the Choices class – for example if it is from an external library? From C# 9 you can follow a similar approach to the above but add the foreach support using an extension method. This way we don’t have to modify the original class.

If the original class that we couldn’t modify looked like the following:

public sealed class Choices
{
    public string FirstChoice { get; set; }
    public string SecondChoice { get; set; }
    public string ThirdChoice { get; set; }
    public string FourthChoice { get; set; }
    public string FifthChoice { get; set; }
}

We could once again create the ChoicesEnumerator class as above and then just create an extension method that adds the GetEnumerator method to the Choices class, without needing to modify the Choices class itself:

public static class ChoicesExtensions
{
    public static ChoicesEnumerator GetEnumerator(this Choices choices)
    {
        return new ChoicesEnumerator(choices);
    }
}

Now we can once again foreach through all the choices.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

ICYMI C# 9 New Features: Reducing Code with Target-typed New Expressions

This is part of a series of articles on new features introduced in C# 9.

C# 9 introduced some enhancements to reduce the amount of code you need when creating new instances of objects.These target-typed new expressions “Do not require type specification for constructors when the type is known.” [MS]

As an example in C# 8 with fields you need to explicitly create an instance:

class Preferences
{
    private List<string> _favoriteColors = new List<string>();
}

From C# 9 you can instead write:

class Preferences
{
    private List<string> _favoriteColors = new();
}

Notice in the preceding code you can simply write new() because the target type is known to be List<string>.

If you are calling a method (or constructor) that requires an instance of an object, you can also use new(). For example suppose you had the following method that requires a DisplayOptions instance:

public void DisplayColors(DisplayOptions options)
{
    Console.WriteLine(options.Title);
    foreach (var color in _favoriteColors)
    {
        Console.WriteLine(color);
    }
}

Prior to C# 9, if you wanted to just create a new instance of DisplayOptions and pass it in you would write:

var prefs = new Preferences();            
prefs.DisplayColors(new DisplayOptions());

With C# 9 you can simplify this to:

var prefs = new Preferences();
prefs.DisplayColors(new());

You could also write this using a target-typed new expression for the Preferences instance:

Preferences prefs = new();
prefs.DisplayColors(new());

If you have init only properties you can also use target-typed new expressions:

class DisplayOptions
{
    public string Title { get; init; }
}
DisplayOptions options = new() { Title = "Colors" };

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

ICYMI C# 9 New Features: More Pattern Matching Features

This is part of a series of articles on new features introduced in C# 9.

Pattern matching was introduced in earlier versions of C# and C# 9 continued to evolve this feature. Pattern matching in a more general sense allows you to write an expression and evaluate it to see whether or not it meets some specified characteristic or “pattern”. In some situations pattern matching can reduce the amount of code you need to write and improve readability.

Pattern matching is supported in is expressions, switch statements, and switch expressions.

C# 9 Type Pattern

The type pattern allows your code to perform a runtime check that an expression of a specified type. In C# 9, when using the type pattern you no longer need to assign to a variable or use a discard.

Prior to C# 9:

object o = "hello";
string message = o switch
{
    string _ => "it's a string",
    int _ => "it's an int",
    _ => "it's something else"
};

WriteLine(message);

ReadLine();

Notice in the preceding code the required discards (or variable assignments) _.

From C# 9 this can be simplified to:

object o = "hello";

string message = o switch
{
    string => "it's a string",
    int => "it's an int",
    _ => "it's something else"
};

WriteLine(message);

ReadLine();

Notice that now no discard is required.

Logical, Parenthesized, and Relational Patterns in C# 9

With C# 9 you can now create logical patterns using not, and, or.

Prior to C# 9 you had to write:

if (o != null)
{
    WriteLine(o);
}

From C# 9 you can write:

if (o is not null)
{
    WriteLine(o);
}

As another example, prior to C# 9 you could not write:

if (o is not string)
{
    WriteLine("not a string");
}

Examples of or, and:

string minuteHandDescription = minuteHandValue switch
{
    >=0 and <= 15 => "first quarter",
    >15 and <= 30 => "second quarter",
    >30 and <= 45 => "third quarter",
    (>45 and <=58) or 59 or 60 => "fourth quarter",
    _ => "unknown"
};

Also notice in the preceding code the use of the parenthesized pattern (>45 and <=58) or 59 or 60 to enforce precedence.

The code also makes use of the new C# 9 relational patterns  that include: <, >, <=, and >=.When using these “The right-hand part of a relational pattern must be a constant expression. The constant expression can be of an integer, floating-point, char, or enum type.” [Microsoft]

For more information on patterns check out the C# language reference.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

ICYMI C# 9 New Features: Top-level Statements

This is the first in a series of articles on new features introduced in C#9.

Top-level statements allow you to simplify and remove some of the “ceremony” in your code.

For example, take the following console application written in C#8:

using System.Linq;
using static System.Console;

namespace ConsoleAppCS8
{
    class Program
    {
        static int Main(string[] args)
        {
            string greeting = "";

            if (args.Any())
            {
                greeting = args[0];
            }

            WriteLine("Please enter your name");
            var name = ReadLine();

            var upperName = ConvertToUpper(name);

            WriteLine($"{greeting} {upperName}");

            return 42;
        }

        public static object ConvertToUpper(string name)
        {
            return name.ToUpperInvariant();
        }
    }
}

In the preceding code the “ceremony” consists of things such as the enclosing namespace, the Program class outline, and the Main method itself.

With top-level statements in C# 9 this code can be simplified to the following:

using System.Linq;
using static System.Console;


string greeting = "";

if (args.Any())
{
    greeting = args[0];
}

WriteLine("Please enter your name");
var name = ReadLine();

var upperName = ConvertToUpper(name);

WriteLine($"{greeting} {upperName}");

return 42;


static object ConvertToUpper(string name)
{
return name.ToUpperInvariant();
}

Notice in the C# 9 version that the structure is a lot “flatter” because there are no nested {} from the namespace, class, and Main method.

The application will still act in the same way, there is just less boilerplate code.

Notice that in the top-level version you can still have methods e.g. ConvertToUpper(), you can still return a value return 42; and you can still access any command line arguments greeting = args[0];

Some Considerations

Whilst top-level statement make the application seem more “script like” this may or may not be a good thing from someone learning C# for the very first time, depending on if they have any other prior programming experience.

Behind the scenes, a synthesized entry point into the application is created for you. If you return a value, the synthesized entry point (a bit like the Main method in the C# 8 version) will have a return value and if you use any async code the synthesized entry point will return Task or Task<int> – essentially using top-level statements doesn’t restrict you from the kind of code you can write.

Notice in the C# 8 version the method public static object ConvertToUpper(string name) could be accessed by another class in the console app:

class Class1
{
    public void XYZ()
    {
        Program.ConvertToUpper("ddd");
    }
}

In the C# 9 top-level version the method becomes:

static object ConvertToUpper(string name)
{
  return name.ToUpperInvariant();
}

If we try to write the same Class1 in the C# 9 project we’ll get an error “Error    CS0103    The name 'Program' does not exist in the current context “. We could of course refactor the ConvertToUpper() method into an explicit static class to make it accessible

You can only have one top-level file in a project, and you can’t also have an explicit Main method entry point at the same time without getting a compiler warning.

A file with top level statements can also include namespaces/classes but they must be after the top-level statements.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

New Course Update: Working with Files and Streams in C#

An newly updated version of my Working with Files and Streams in C# video training course is now available. This version includes updated demos to .NET 5.

“C# has so many different ways to work with the file system and read and write data. It can be difficult to know what the best approach is and where to start. This course will teach you how to manipulates files, directories, paths, and streams in C#.”

Start watching with a free trial today.

SHARE:

Free .NET Testing Courses This Month

This month all my Pluralsight courses are available for free including a lot of .NET testing content that can help you either get started with .NET testing or level-up your tests to make them easier to read and more maintainable.

Suggested Courses

Step 1: Learn a base testing framework:

Step 2: Level-up the base testing framework:

Step 3: Power-ups to complete your test strategy

Bonus Step: Help convince your co-workers and managers to let you write tests with the Testing Automation: The Big Picture course.

SHARE:

Exception Handling in C# Course Update

An updated version of my Exception Handling in C# course is now available that updates demos to to use .NET 5.

From the course description: “At the core of handling errors in C# code is a thorough knowledge of exception handling. In this course, Error Handling in C# with Exceptions, you’ll learn how to write code that can detect and respond to runtime errors. First, you’ll learn why exceptions are used to represent errors in C# and how they are organized into class hierarchies. Next, you’ll explore how to throw, catch, filter, rethrow, and wrap exceptions. Finally, you’ll discover how to define, throw, and catch your own customized exception classes and also write unit tests for exception throwing code. When you’re finished with this course, you’ll have a thorough knowledge of C# exceptions that will help you to create production-ready C# applications that detect and respond to runtime errors.”

You can start watching the course with a free trial.

SHARE:

ICYMI C# 8 New Features: Asynchronous Streams

This is part 8 in a series of articles.

In earlier versions of C# you could return an IEnumerable<T> from a method, for example to be consumed by a foreach loop.

The following example shows a method from a WPF app that returns 3 web pages as string content:

public static IEnumerable<string> LoadWebPages()
{
    using (var client = new HttpClient())
    {
        yield return client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Switch-Expressions").Result;
        yield return client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations").Result;
        yield return client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations").Result;
    }
}

This method could be used in a click event handler in the WPF app (or via MVVM etc.):

private void NotAsync_Click(object sender, RoutedEventArgs e)
{
    foreach (var page in WebPageLoader.LoadWebPages())
    {
        var titleIndex = page.IndexOf("<title>");
        txt.Text += Environment.NewLine + $"Got page: {page.Substring(titleIndex, 110)}";
    }
}

When you run the app and click the button, the 3 web pages will be loaded and added to the content of the <TextBlock x:Name="txt"></TextBlock>

While loading the 3 web pages and looping through the foreach loop however, the app will be unresponsive until all 3 pages have been returned in the foreach loop.

C# 8 introduced the ability to use the IAsyncEnumerable<T> interface to iterate items asynchronously.

The “asynchronous streams” feature of C# 8 should not be confused with the streams in the System.IO namespace.

The LoadWebPages method can be re-written in C# 8 as:

public static async IAsyncEnumerable<string> LoadWebPagesAsync()
{
    using var client = new HttpClient();

    yield return await client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Switch-Expressions");
    yield return await client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations");
    yield return await client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Simplify-If-Statements-with-Property-Pattern-Matching");
}

And to consume this version:

private async void Async_Click(object sender, RoutedEventArgs e)
{
    await foreach (var page in WebPageLoader.LoadWebPagesAsync())
    {
        var titleIndex = page.IndexOf("<title>");
        txt.Text += Environment.NewLine + $"Got page: {page.Substring(titleIndex, 110)}";
    }
}

Now when the <Button Content="Async" x:Name="Async" Click="Async_Click"></Button> button is clicked, the 3 webpages will be enumerated in an async manner meaning that the UI will remain responsive.

The IAsyncEnumerable<T> interface also provides for cancellation: IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE: