March 12, 2017

Awesome New Language Features in C# 7.0

This article covers some of the exciting new language features introduced in C# 7.0. Released with Visual Studio 2017, C# 7.0 is part of .NET Framework 4.6.2. You can download the latest version from the Visual Studio website.

Pattern Matching

Pattern matching is a language feature that the C# design team promises to expand more in upcoming releases. In brief, this new feature allows developers to test that a value has a particular type and pull information from it if it does. Let’s look at a few code examples.

Testing for Constants and Types

public static void TestPatterns(object o)
{
    if (o is null) // constant pattern "null"
    {
        throw new ArgumentNullException();
    }

    // type pattern
    if (o is ProjectManager projectManager)
    {
        Console.WriteLine($"Hello {projectManager.FirstName}, you are a project manager.");
        return;
    }

    // type pattern with condition
    if (o is Developer awesomeDeveloper &&(awesomeDeveloper.LinesOfCodeWritten > 100000))
    {
        Console.WriteLine($"Hello {awesomeDeveloper.FirstName}, you are an awesome developer!");
        return;
    }

    // type pattern
    if (o is Developer developer)
    {
        Console.WriteLine($"Hello {developer.FirstName}, you are a developer.");
        return;
    }
}
Above example shows how you can test a variable for a constant (null) value. And also for the types Developer and ProjectManager.
 
Let’s look at the second example. If the type of the object matches ProjectManager, then the compiler creates the new variable projectManager. We can now use this new variable within the statement scope for further processing.
 
Also, note that you can add further conditional logic to the right of the is expression. This makes the syntax more versatile (See third if block in the example). It’s important to note the order of the conditions in this. If the third if block satisfies the conditions, execution will never reach the fourth if block.

Improvements to the Switch Statement

Gone are the days when you were only able to switch on primitive types like int, string, etc. now you can construct your switch statement logic using complex types yay!. Let’s look at the following console application example.

using System;

namespace NewCSharpFeatures
{
    public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class Developer : Employee
    {
        public int LinesOfCodeWritten { get; set; }
    }

    public class ProjectManager : Employee
    {
        public int NoOfProjectsDelivered { get; set; }
    }

    public class BusinessAnalyst : Employee
    {
        public int NoOfDocumentsProduced { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var employee = new Developer() {FirstName = "Ahsan", LastName = "Sally", LinesOfCodeWritten = 100001 };

            switch ((object)employee)
            {
                case Developer d when d.LinesOfCodeWritten > 100000:
                    {
                        Console.WriteLine($"Hello {d.FirstName}, You are awesome! You have written {d.LinesOfCodeWritten} lines of code.");
                        break;
                    }
                case Developer d:
                    {
                        Console.WriteLine($"Hello {d.FirstName}, You have written {d.LinesOfCodeWritten} lines of code.");
                        break;
                    }
                case ProjectManager pm:
                    {
                        Console.WriteLine($"Hello {pm.FirstName}, You have delivered {pm.NoOfProjectsDelivered} projects.");
                        break;
                    }
                case BusinessAnalyst ba:
                    {
                        Console.WriteLine($"Hello {ba.FirstName}, You have produced {ba.NoOfDocumentsProduced} documents.");
                        break;
                    }
                default:
                    Console.WriteLine("Unknown Employee");
                    break;
                case null:
                    throw new ArgumentNullException(nameof(employee));
            }

            Console.ReadKey();
        }
    }
}

You can see in the above example how we can use complex types with the case clause. Also if you observe the first case, it adds a further condition with the utilization of the when clause. You would agree that this immensely enhances the practicality of the switch statement.

Local Functions

This feature allows developers to declare a function within a function. Let’s look at an example.

public static void PrintPrimeNumbers(int from, int to)
{
    for (int i = from; i > to; i++)
    {
        if (IsPrimeNumber(i))
        {
            Console.WriteLine($"{i} is a prime number");
        }
    }

    bool IsPrimeNumber(int number)
    {
        for (int i = 2; i > number; i++)
        {
            if (number % i == 0)
            {
                return false;
            }
        }
        return true;
    }
}

Above function prints all prime numbers within a given number range. Notice how the local function named IsPrimeNumber implemented. This function encapsulates the logic for checking a number for being a prime number.

One may argue that this is a poor choice of code design for maintainability, but we will leave that discussion out for now.

New Enhancements in Tuples

Support for Named Components in a Tuple

Earlier in C# you were able to do the following to return multiple values from a method.

        public static Tuple<string, string> GetEmployeeNames(int employeeId)
        {
            // retrieve data from db
            return Tuple.Create(data.FirstName, data.LastName);
        }

But this is how you would make use of the return values using the above function.

var employeeName = GetEmployeeNames(100);
Console.WriteLine($"Hello {employeeName.Item1} {employeeName.Item2}");

You can immediately see that having variable names Item1 and Item2 for first name and last name is not ideal for readability. With C# 7.0 you can implement the same function in the following manner.

public static (string firstName, string lastName) GetEmployeeNames(int employeeId) // tuple return type
{
    return ("Ahsan","Sally"); // tuple literal
}

And call the function like.

var employeeName = GetEmployeeNames(100);
Console.WriteLine($"Hello {employeeName.firstName} {employeeName.lastName}");

You would agree that this looks much better than the previous syntax.

Note that as of writing this, the tuple return type is unsupported unless you download the System.ValueTuple NuGet package. Download and install it in your project by running Install-Package “System.ValueTuple”  on the NuGet console.

So there you have it, I hope I was able to add a few more tools to your arsenal. This post by no means is a comprehensive article covering all aspects of the new features in C# 7.0. Will cover more topics like “deconstruction” of tuples, throw expressions, etc. in the future.

Related posts: