pattern matching in c# 8

In this blog post we’re going to be looking at one of the features released in C# 8.0, supported on .NET Core 3.x and .NET Standard 2.1. I’m talking about the latest improvements done to pattern matching. Pattern matching, a core concept in software development, is the evaluation of data during run time and basing the flow of the program based on that outcome. A common way to do this in C# is to use an if or a switch statement, which I’m sure you did if you’re reading this blog post.

This was originally introduced in C# 7.0 with the introduction of the is keyword. The is keyword was introduced to evaluate for type patterns (checks an object’s type), constant patterns (compares a value to a constant) and var patterns (match that always succeeds and binds the value of an expression to a new local variable). C# 8.0 adds new functionality to the current syntax and techniques.

Switch Expressions

Starting with the introduction of switch expressions, up until C# 8.0 this is how we would normally make use of a switch statement.


private static SportType GetSport(string ballSize)
{
switch (ballSize)
{
case "tiny":
return SportType.Golf;
case "small":
return SportType.Tennis;
case "medium":
return SportType.Volleyball;
case "large":
return SportType.Football;
case "extra large":
return SportType.Basketball;
default:
throw new ArgumentException("invalid ball properties");
}
}

We have a method that checks the value of the string variable, representing a ball size, and returns an enum, representing a sport, based on the following enum.


public enum SportType
{
Golf,
Tennis,
Volleyball,
Football,
Basketball,
AmericanFootball,
Rugby
}

The following is the same implementation as above but with the new switch expressions.


private static SportType GetSport(string ballSize)
{
return ballSize switch
{
"tiny" => SportType.Golf,
"small" => SportType.Tennis,
"medium" => SportType.Volleyball,
"large" => SportType.Football,
"extra large" => SportType.Basketball,
_ => throw new ArgumentException("invalid ball properties")
};
}

The main differences are

  • The evaluating variable comes before the switch keyword. An easy way to distinguish between a switch statement and a switch expression.
  • The case and : syntax elements are replaced with =>.
  • The default case is replaced with a _ discard. Introduced in C# 7.0
  • The bodies are expressions not statements.

Property Patterns

In property patterns we’ll now look at how to evaluate the value of a property inside an object. Let’s consider the following class, based on the same sport/ball size example. For the time being ignore the property BallShape.


public class Sport
{
public string BallSize { get; set; }
public string BallShape { get; set; }
public SportType Name { get; set; }
public Sport(string size, string shape)
{
BallSize = size;
BallShape = shape;
}
}

Based on the above Sport class, if we had to evaluate the BallSize property inside a switch expression, this is how it will look.


private static SportType GetSport(Sport sport)
{
return sport switch
{
{ BallSize: "tiny" } => SportType.Golf,
{ BallSize: "small" } => SportType.Tennis,
{ BallSize: "medium" } => SportType.Volleyball,
{ BallSize: "large" } => SportType.Football,
{ BallSize: "extra large" } => SportType.Basketball,
_ => throw new ArgumentException("invalid ball properties")
};
}

The switch expression provides a cleaner and shorter solution to the traditional switch statement applied to an object’s property, which for comparison I have added below.


private static SportType GetSportPropertyOld(Sport sport)
{
switch (sport.BallSize)
{
case "tiny":
return SportType.Golf;
case "small":
return SportType.Tennis;
case "medium":
return SportType.Volleyball;
case "large":
return SportType.Football;
case "extra medium":
return SportType.Basketball;
default:
throw new ArgumentException("invalid ball properties");
}
}

Tuple Patterns

Finally, we are going to introduce another value to evaluate and this will open up more patterns and options. Besides checking for the ball size, we’ll also be checking for the ball shape. A tuple is the ideal type to use as it holds two values, and this is how you would evaluate a tuple using a switch expression.


private static SportType GetSport((string, string) ballProperties)
{
return ballProperties switch
{
("tiny", "round") => SportType.Golf,
("small", "round") => SportType.Tennis,
("medium", "round") => SportType.Volleyball,
("large", "round") => SportType.Football,
("extra large", "round") => SportType.Basketball,
("medium", "oval") => SportType.AmericanFootball,
("large", "oval") => SportType.Rugby,
_ => throw new ArgumentException("invalid ball properties")
};
}

Again, for clarification, this was possible before but I’m sure you would agree with me saying that it wasn’t the cleanest solution. Here’s the more traditional approach.


private static SportType GetSport((string, string) ballProperties)
{
switch (ballProperties)
{
case var b when b == ("tiny", "round"):
return SportType.Golf;
case var b when b == ("small", "round"):
return SportType.Tennis;
case var b when b == ("medium", "round"):
return SportType.Volleyball;
case var b when b == ("large", "round"):
return SportType.Football;
case var b when b == ("extra large", "round"):
return SportType.Basketball;
case var b when b == ("medium", "oval"):
return SportType.AmericanFootball;
case var b when b == ("large", "oval"):
return SportType.Rugby;
default:
throw new ArgumentException("invalid ball properties");
}
}

That’s it in terms of pattern matching in C# 8.0. Personally I welcome these new features as I think it provides better functionality, and a cleaner solution too! For more information about C# 8.0, or different examples of pattern matching, check out this article in Microsoft Docs.

Thanks for reading and until the next blog post,
Bjorn

debugging better using breakpoints and the output window

Debugging, love it or hate it! Debugging is a skill that you won’t learn by reading a book but a skill that you perfect through practice (cliche, am I right?). It also makes you think outside the box in order to understand the issue better. Having said that I am guilty of finding a technique and sticking with it without being aware that there are better ways. Well recently I discovered a feature in Visual Studio that is efficient and helpful. I’m talking about breakpoint actions and tracepoints. What really blew my mind is that this feature has been around for quite a few years now (hence why I said I’ll stick with a technique) but for some reason I never really discovered it or used its full potential. Consider the following program, very straight forward but with long iterations.


class Program
{
static void Main(string[] args)
{
var status = "";
for (int i = 0; i < 1000; i++)
{
if (i < 100)
{
status = "first hundred";
}
else if (i < 200)
{
status = "second hundred";
}
else if (i < 300)
{
status = "third hundred";
}
else if (i < 1000)
{
status = "the rest";
}
}
System.Diagnostics.Debug.WriteLine("end of loop");
Console.ReadLine();
}
}

Breakpoint actions

First thing we want to debug, and are interested in, is to know what the value of the iterator i is every time the value of the variable status changed. In that case we would set up a break point like below. Instead of stopping execution I decided to output the value of i in the output window.

debuggingone

Another approach, given that we are looping for a thousand times, would be to stop, or output a value, when the iteration hits a specific point. In my case when the value of i is equal to 567, and again I decided to output the value of status in the output window using string interpolation.

debuggingtwo

Writing values in the output window

Sometimes you might not be interested in stopping the execution of the program, and in that case using the output window is a good way to analyse the values of your variables. Simply add the following snippet to any point in your source code where execution is happening and you should be able to see the results in your Visual Studio output window. Be sure to have Debug selected in the drop-down list.

System.Diagnostics.Debug.WriteLine("hard coded string or " + yourVariable);

Results

After setting all your breakpoints with specific conditions, you are now ready to run the program. The outcome should be similar to the the following.

debuggingthree

That’s me done debugging for the day, hope you found this post helpful and see you in the next post.
Bjorn

writing a fluent validation custom validator with multiple parameters

FluentValidation is a .NET framework used to validate objects and values of properties inside an object. It allows you to write different rules without much effort thanks to its out of the box rule sets validators. However different properties require different validation rules, and FluentValidation allows for custom validators to be written, which again I think it’s great. Having said that, I recently needed to write a validation rule set for a property that depended also on the value of another property (in the same object).

Here’s what I came up with in a scenario where a DTO is received in an API endpoint used when users purchase Playstation games.


public class PurchasePlaystationGameDto
{
public int ID { get; set; }
public int UserID { get; set; }
public decimal Price { get; set; }
public bool PlaystationPlusMember { get; set; }
}
public class PurchasePlaystationGameDtoValidator : AbstractValidator
{
public PurchasePlaystationGameDtoValidator()
{
RuleFor(x => x.ID).NotNull().GreaterThan(0).WithMessage("ID must be greater than 0.");
RuleFor(x => x.UserID).NotNull().GreaterThan(0).WithMessage("UserID must be greater than 0.");
RuleFor(x => x.Price).Must(BeGreaterThanZeroForNonMembers).WithMessage("Price must be greater than 0");
}
private bool BeGreaterThanZeroForNonMembers(PurchasePlaystationGameDto dtoInstance, decimal price)
{
// game is free for members 🙂
if (!dtoInstance.PlaystationPlusMember & price <= 0)
{
return false;
}
return true;
}
}

Simple and straight forward, if the user is a Playstation plus member then the price can be zero as the member is eligible for a free game.

That’s a wrap, until next post.
Bjorn

mocking a method to return different results

This week I was working on a piece of code that process batches and it had to be unit tested. Let’s think of this scenario. We have a service endpoint that creates a batch order (and a record in the database), and then for each item in that batch order it will create a product order (and again, a record in the database). If one of the product order fails, we need to revert the process, and delete all product orders together with the batch order.

Implementing it wasn’t a problem but when it came to unit testing the behaviour in the case when one product order fails, I had to think twice about it. Thankfully I discovered the SetupSequence method in the testing framework that I use (xUnit). What this method does is basically saying that when a method is called, I want the first value to be something, and the second value to be something else, in my case zero. I then decided to assert that not only the return would be zero (because the whole batch failed) but also that the method that reverts the transaction was called. Check out my implementation below;


[Fact]
public async void TheMethodImMocking_Returns_Zero_If_One_Of_The_Records_Not_Inserted()
{
// Arrange
Mock _mockDataLayerService = new Mock;
_mockDataLayerService.SetupSequence(x => x.ProcessIndividualOrder(It.IsAny())).ReturnsAsync(9999).ReturnsAsync(0);
// Act
var batchProcessingService = new BatchProcessingService(_mockDataLayerService.Object);
var result = batchProcessingService.ProcessBatchOrder()
// Assert
Assert.IsType(result);
Assert.Equal(0, result);
_mockDataLayerService.Verify(m => m.ReverseOrderProcessing(It.IsAny()), Times.Exactly(1));
}

The only catch when using the SetupSequence method is to know how many times the testable method will be called because if the return values, and the amount of calls do not match, an exception will be throw. Again, in my case I knew that I will be calling the method ProcessIndividualOrder twice so I setup the method to return a value twice.

I hope you’ll find this useful the same way I did, and happy unit testing 🙂

Bjorn

implementing a cascading dropdown list with MVC and Jquery

By definition (my own) a cascading dropdown list(s) is a set of dropdown list(s) dependent on their parent dropdown list. In this blog post we’ll see how this can be achieved in ASP.NET’s MVC pattern, with the help of some client-side scripting too. For simplicity I will be using the standard template that Visual Studio creates for you when you create a new project. Also, I uploaded the source code to this GitHub location.

All right so let’s say that we’re going to have three dropdown lists, and through these we will be able to drill down from continent, to countries, to cities. All the data in this project is hard coded but it can easily be retrieved from a database or some other source. So first thing we’ll do is update the Index method in the HomeController to make it look like the following;


public ActionResult Index()
{
continents = new List();
continents.Add(new SelectListItem { Text = "Select continent", Value = "0" });
continents.Add(new SelectListItem { Text = "Europe", Value = "1" });
continents.Add(new SelectListItem { Text = "North America", Value = "2" });
continents.Add(new SelectListItem { Text = "South America", Value = "3" });
ViewData["continents"] = continents;
countries = new List();
countries.Add(new SelectListItem { Text = "Select country", Value = "0" });
ViewData["countries"] = countries;
cities = new List();
cities.Add(new SelectListItem { Text = "Select city", Value = "0" });
ViewData["cities"] = cities;
return View();
}

So we created three lists of type SelectListItem and filling them with some data, and then passing them to our view using the ViewData. These lists can also be bound to a model and then pass the model to the view. I chose the ViewData option for simplicity. Within the view we need to create three dropdown lists and make a reference to the ViewData.


<div class="row">
<div class="col-md-4">
@Html.DropDownList("continents", ViewData["continents"] as List)
</div>
<div class="col-md-4">
@Html.DropDownList("countries", ViewData["countries"] as List)
</div>
<div class="col-md-4">
@Html.DropDownList("cities", ViewData["cities"] as List)
</div>
</div>

Now we got three dropdown lists with some data in them. For the next part we need to add some client-side scripting so we can load more data dynamically. Using Jquery we will make an AJAX call and get data according to what the user selected.


$("#continents").change(function () {
$("#countries").empty();
$.ajax({
type: 'POST',
url: '/Home/GetCountries',
dataType: 'json',
data: { selectedValue: $("#continents").val() },
success: function (areas) {
$.each(areas, function (i, area) {
$("#countries").append('' + area.Text + '');
});
},
error: function (ex) {
alert('Failed to retrieve countries.' + ex);
}
});
return false;
});
$("#countries").change(function () {
$("#cities").empty();
$.ajax({
type: 'POST',
url: '/Home/GetCities',
dataType: 'json',
data: { selectedValue: $("#countries").val() },
success: function (cases) {
$.each(cases, function (i, ucase) {
$("#cities").append('' + ucase.Text + '');
});
},
error: function (ex) {
alert('Failed to retrieve cities.' + ex);
}
});
return false;
});

Back to the HomeController we are going to create two entry points and do our logic in there.


public JsonResult GetCountries(string selectedValue)
{
countries = new List();
countries.Add(new SelectListItem { Text = "Select country", Value = "0" });
switch (selectedValue)
{
case "1":
countries.Add(new SelectListItem { Text = "United Kingdom", Value = "1" });
countries.Add(new SelectListItem { Text = "Italy", Value = "2" });
countries.Add(new SelectListItem { Text = "Greece", Value = "3" });
break;
case "2":
// more countries
break;
case "3":
// more countries
break;
}
return Json(new SelectList(countries, "Value", "Text"));
}
public JsonResult GetCities(string selectedValue)
{
cities = new List();
cities.Add(new SelectListItem { Text = "Select city", Value = "0" });
switch (selectedValue)
{
case "1":
cities.Add(new SelectListItem { Text = "Glasgow", Value = "1" });
cities.Add(new SelectListItem { Text = "London", Value = "2" });
cities.Add(new SelectListItem { Text = "Edinburgh", Value = "3" });
break;
case "2":
// more cities
break;
case "3":
// more cities
break;
case "4":
// more cities
break;
case "5":
// more cities
break;
// more cases
}
return Json(new SelectList(cities, "Value", "Text"));
}

And that should be it. Feel free to share your thoughts if you have any suggestions. Until the next post.

Bjorn