Image for post
Image for post
An example of switch expressions in C# 8.0

How C# 8 Helps Software Quality

Matt Eland
Oct 9, 2019 · 7 min read

.NET Core 3 is a major milestone in .NET and with it, brings some exciting new functionality — most notably with the arrival of C# 8.

I want to offer my own perspective on this release and specifically how C# 8 helps with software quality.

Note that by software quality, I mean the overall quality of delivered software, not code quality which relates to the maintainability and readability of our source code.

C# 8.0

The new set of features are dependent on changes inside of the .NET runtime, which means that the new language features we’ll be discussing here are not available for .NET Framework or Visual Studio 2017 or earlier at this time.

So, that’s the bad news.

The good news is that C# 8 is a very feature-rich update that has some very exciting features for all aspects of software development.

I won’t be talking about everything new in C# 8, but the most significant language features that can improve software quality. Specifically, I’m going to be focusing on:

  • Nullable Reference Types
  • Null Coalescing Assignments
  • Readonly Members
  • Switch Expressions & Pattern Matching

As we go, we’ll look at what each of these are and what they can do to improve software quality.

Nullable Reference Types

Let me explain.

In C# a reference type either holds a reference to an object or it is null. That means that for things that can be null, you need to check if the object is present at all before you try to interact with it. If you don't, you receive the infamous NullReferenceException.

C# 8.0 offers you a new option on this. You can enable non-nullable reference types in your code either via a project setting or pre-processor statements and Visual Studio 2019 will automatically assume that reference types declared can never be null unless you explicitly tell it via adding ? to the type declaration.

Let’s look at a simple class:

In the above example, SomeNonNullValue is assumed to never contain a null value because it lacks the ? syntax and Visual Studio will warn you if it notices you checking it for null or setting something into it that it thinks could be null.

Conversely, SomeNullableValue is interpreted as potentially having a null value since it is indicated with the ? syntax.

The reason that the nullable preprocessor statements are present is because most people working with legacy code can't activate this feature for their entire codebase at once, so these regions let you enable or disable the functionality as needed.

Why This Matters for Quality

The impacts of this feature are huge as far as removing unnecessary null checks from code and, more importantly, ensuring that things are properly checked for null at time of development.

This new language feature offers the possibility of removing or vastly reducing entire classes of errors from code, which is always a good thing.

I personally love this new syntax and find the parallels it offers to TypeScript type definitions very appealing.

If you’d like more information on getting started with these, take a look at my in-depth article on nullable reference types in C# 8.0.

Null Coalescing Assignments

Coalescing refers to bringing things together to form one whole. C# already supports a number of null operators from the simple ?. to safely access properties on objects which may or may not be null to the ?? coalescing operator to use one value if the first is null.

The null coalescing assignment operator, ??= builds slightly on these by addressing a specific scenario.

Say you have code where you want to check if something is null and if it is, you want to assign it a value.

In normal C# syntax you might do the following:

We can simplify this code using the null coalescing assignment operator to the following:

Why This Matters for Quality

This hurts readability slightly to those unfamiliar with ??= (which right now is most everyone), but this also makes parameter default value assignment logic a lot more concise allowing more vertical space for the actual meat of the method.

Additionally, this prevents copy and paste mistakes that you might see where you check one variable for null but assign a value to another in case of null.

This sounds far-fetched, but this sort of “duplicate a block of code then fail to change all necessary areas” type of behavior is a frequent cause of bugs in many systems.

Readonly Members

Readonly members, on the other hand, are properties or method defined as not being allowed to change the state of the instance they’re associated with. This sounds a lot like Pure logic, and most implementations will be, but there’s not promise that a readonly member won’t modify the state of another object besides its own instance.

Let’s take a look at this in action:

Here we define the CalculateFooPlusFortyTwo method as readonly which prevents it from modifying any instance state at the compiler level. Let's say some future programmer tried to change the code to the following:

In this example, the code wouldn’t compile because the logic was trying to modify the Foo property when the method is defined as readonly.

Why This Matters for Quality

Readonly is important for two major reasons:

  1. It prevents you from accidentally changing internal state in places where that was not expected (most property getters for example).
  2. It more clearly communicates the intent of your code to other code.

By that second point, let’s take a look at the DateTime.AddDays() method. To those not familiar, this method will take the DateTime instance's date, add X days to it, and then return the new date. Many beginners assume that calling AddDays on an object will increment that object's date reference to the new value, but this is a common .NET gotcha.

Let’s say the AddDays method was instead defined as readonly. In that case, the caller would know more clearly that the method doesn't modify the internal state of the date instance and it'd be another clue to the uninitiated as to the behavior of the class.

Switch Expressions & Pattern Matching

A switch statement is pretty standard knowledge for most developers.

The problem is that there’s a lot of repetitive syntax in a switch statement that gets a little boring. Additionally, switches can make you have to do some interesting logic at times inside of case statements to disambiguate, as we saw with the Thing entry in the example above.

C# 8 offers a lot more flexibility and conciseness in switch statements.

For example, I could rewrite the above example as:

First of all, this is significantly shorter. Second of all, the conditional logic possible via when helps us separate two ambiguous cases more cleanly.

Additionally, the logic is even more powerful than displayed above. Let’s say instead of knowing the class, you had to switch on something that was an Object or some abstract type.

Take a look at the Vehicle pricing example below:

Here we can actually switch off of the concrete object and its properties. That’s fairly powerful, yet concise logic.

Why This Matters for Quality

At first glance you wouldn’t think that these “syntax sugar” improvements would do too much for actual software quality, but I think we as developers often underestimate the impact that boiler-plate logic and syntax have on software quality and code maintainability.

Let me put it this way: If I don’t have to write a line of code, I won’t make a mistake on that line that I have a chance of never catching until it gets to production.

By using switch language syntax and conciseness, I’m relying on .NET to do the casting and matching for me without having to write custom logic for that (and potentially get it wrong).

Additionally, by compressing the boiler-plate logic into a smaller region of code, it puts more emphasis on the program logic that actually matters, which means that more attention gets put on our application logic during code review and during debugging sessions which increases the odds that defects in those blocks will be found.

Closing

There are many more new features in C# 8. If you’d like to learn more, I recommend you read Microsoft’s What’s new in C# 8.0 article.

What features are you most excited to use? What features have you found helpful in increasing your code quality?

Originally published at https://KillAllDefects.com on October 9, 2019.

The Startup

Medium's largest active publication, followed by +734K people. Follow to join our community.

Matt Eland

Written by

After over three decades of software engineering, Matt put away his mechanical keyboard and made teaching his primary job as he looks to help others grow.

The Startup

Medium's largest active publication, followed by +734K people. Follow to join our community.

Matt Eland

Written by

After over three decades of software engineering, Matt put away his mechanical keyboard and made teaching his primary job as he looks to help others grow.

The Startup

Medium's largest active publication, followed by +734K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store