Pattern matching in C# 7.0

C# 7.0 introduces a new language feature called pattern matching. If you are familiar with F# then you’ll know what pattern matching is about. Pattern matching is used extensively in F# but has not been available in C# before 7.0. Also, pattern matching is not just a simple feature in F#, but more like a wide range of features. However, C# 7.0 has not yet caught up with all that. C# 7.0 only introduces a small set of features behind pattern matching and can be regarded as syntactic sugar, but it’s a good start. I’d expect that the same F# features will eventually be transferred into C# as well in upcoming updates.

Pattern matching is most often used in “if” or “switch” branches to see if an incoming value matches a certain pattern. If it does then we take that path, otherwise we take another.

Let’s start with a starting point with a base class and two derived classes:

public abstract class Animal
{

}

public class Dog : Animal
{
	public void Whoof()
	{
		Console.WriteLine("The dog is barking");
	}
}

public class Cat : Animal
{
	public void Meow()
	{
		Console.WriteLine("The cat is meowing");
	}

	public String Colour { get; set; }
}

That should be fairly easy to follow: Dog and Cat both derive from Animal. However, Dog has a Whoof function and Cat has a Meow function. So if there’s a collection with Animal objects then we cannot call them without casting. This leads to the classic code design error where despite our good intentions to work with abstractions we have to check the exact type of an object. Breaking the SOLID principles is, however, not the topic of this post, so let’s continue. Here’s a function where we check the type of an abstraction, cast it to its concrete type and call either the Whoof or Meow method on it:

private void MakeAnimalSoundOldWay(Animal animal)
{
	//use the "is" keyword to find the correct type
	if (animal is Dog)
	{
		Dog dog = (Dog)animal;
		dog.Whoof();
	}
	else if (animal is Cat)
	{
		Cat cat = (Cat)animal;
		cat.Meow();
	}

	//or use the "as" keyword and check for null
	Dog d = animal as Dog;
	if (d != null)
	{
		d.Whoof();
	}

	Cat c = animal as Cat;
	if (c != null)
	{
		c.Meow();
	}
}

We can achieve the type checking with either the “is” or the “as” keyword. With “is” we check the concrete type of the object. With “as” we need to check if the object is null or not.

C# 7.0 introduces a short-hand solution for the “is” solution where we can get rid of the cast:

if (animal is Dog dog)
{
	dog.Whoof();
}
else if (animal is Cat cat)
{
	cat.Meow();
}

So if “animal” is a Dog then “dog” will be the downcast Dog object.

We can also solve this case with a switch statement where we see the usage of the “when” keyword:

switch (animal)
{
	case Dog d:
		d.Whoof();
		break;
	case Cat c when (c.Colour == "white"):
		Console.WriteLine("I am a white cat");
		c.Meow();
		break;
}

With “when” we can fine-grain our code branching logic. If “animal” is a Cat and its colour is white then do something. If it is a Cat but its colour is black then this code path won’t be taken.

With C# 7.1 we can introduce generics into our pattern matching code. Make sure that the C# build version of your project is set to 7.1 otherwise this code will not compile:

private void MakeAnimalSoundNewWayWithGenerics<T>(T animal) where T : Animal
{
	if (animal is Dog d)
	{
		d.Whoof();
	}
}

We can call the above function as follows:

MakeAnimalSoundNewWayWithGenerics(new Dog());

View all various C# language feature related posts here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

2 Responses to Pattern matching in C# 7.0

  1. Yan says:

    Andras, thanks for this! really useful. i notices this very feature a while ago as a result of a great VS2017 feature – it automatically suggested this syntax to me when i was trying to do it the “old way” and refactored it. really nice of VS2017.

  2. Tracy Woo says:

    Thanks a lot Andreas! for sharing your thoughts with us I found that post very helpful for myself.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT BEST PRACTICES WITH MICROSOFT STACK & ANGULAR

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: