Kriya and Meditation for Software / IT Professionals. Conducted by Bipin Joshi in Thane. Read more...
Learn ASP.NET MVC, ASP.NET Core and ASP.NET Design Patterns. Courses conducted by Bipin Joshi on weekends. Click here for more details.

7 Features of C# 7.0 Worth Knowing

As you are aware of C# 7.0 and Visual Studio 2017 have been released. In this article I quickly take you through seven new features of the language that are worth knowing. I assume that you are familiar with C# 6.0 and hence I am not going into too much technical details of these features here. My aim is to quickly let you know of a few interesting features that can make your C# code more efficient and clear. Let's get going.

1. Tuple types and Tuple literals

At times you need to return more than one values from a method. Developers used different techniques to achieve that. Tuples was one of them. In C# 7.0 returning a tuple from a method is easy as shown below :

private (string s1,string s2,string s3) GetLanguages()
{
    return ("C#","VB.NET","F#");
}

The GetLanguages() method returns a tuple literal that contains three values. Notice how the method return type has been specified using the new tuple type syntax.

The tuple thus returned can be accessed like this :

var retVal = GetLanguages();
MessageBox.Show($"{retVal.s1} - 
{retVal.s2} - {retVal.s3}");

Note that to work with this example you may need to add System.ValueTuple NuGet package. 

2. Local functions

At times you need to execute a bunch of statements or logic multiple times. Ordinarily you would create a private helper method and call that method as and when needed. But what if that logic is needed multiple times only in a single method? That's where local functions can be useful.

As the name suggests a local function is a function that exists locally to another function. It's like a function inside a function. Let's create one and understand the how they work:

public void DoWork()
{
  string GetRandomCode()
  {
    return "ABC" + new Random().Next();
  }

  string code1 = GetRandomCode();
  string code2 = GetRandomCode();
  string code3 = GetRandomCode();

  MessageBox.Show($"{code1} - {code2} - {code3}");
}

The DoWork() is the main function doing some lengthy work. Inside, we create GetRandomCode() function. This is a local function and here simply generates a random string code.  GetRandomCode() is called multiples times by the other parts of DoWork(). Obviously, GetRandomCode() won't be accessible to withinn the other methods.

3. Enhancements to is-expressions and switch statement

C# 7.0 introduces what is known as pattern matching - a feature that allows you to test a value for certain shape and also extract information form that value.

Currently pattern matching is being introduced in two ways but in the future more might get added. The two constructs that got enhanced with pattern matching are is-expressions and switch statement. Consider the following code :

private void ShowType(object param)
{
    string msg = "";

    if(param is null)
    {
        msg = "Value is null.";
    }

    if (param is int a)
    {
        msg = $"Value is integer - {a}";
    }

    if(param is string s)
    {
        msg = $"Value is string - {s}";
    }

    MessageBox.Show(msg);
}

The ShowType() method accepts an object parameter. Inside, three if blocks test for certain pattern and assign the msg variable accordingly.

  • The first if statement used constant pattern that checks the value of the parameter against constant - null.
  • The second if statement uses type pattern and tests whether the parameter is an integer. Further, it puts the value of the parameter into a if it is indeed an integer.
  • The third if statement works quite similar to the second one but tests against string data type.

You can use the pattern variables (a and s in the above example) inside the respective blocks to retrieve their values.

Now consider a switch statement that uses patterns :

private void ShowData(object param)
{
    string msg = "";

    switch(param)
    {
        case Employee e:
            msg = $"Employee - {e.FirstName}
                     {e.LastName}";
            break;
        case Customer c:
            msg = $"Customer - {c.CustomerID} 
                  {c.CompanyName}";
            break;
        case Order o:
            msg = $"Order - #{o.OrderID} 
           {o.CustomerID} {o.OrderDate}";
            break;
        case null:
            msg = $"Data is null.";
            break;
        default:
            msg = "Unknown data.";
            break;
    }

    MessageBox.Show(msg);
}

As is clear from the switch statement, you can now use any types in the statement. The individual case clauses uses patterns to test the param against certain type or a constant (Employee, Customer, Order, null etc.). You can access the pattern variables inside the individual case blocks as before. Remember that with this arrangement the order in which the case clauses appear matters. If some cause meets the pattern further case clauses won't be evaluated.

4. Deconstruction

While constructing an object you typically pass values to it and then assign those values to the internal members of the class. Deconstruction does exactly opposite. It retrieves values from an object and assigns them to variables. Let's understand this with an example.

Consider the following Employee class :

class Employee
{
    public int EmployeeID { get; set;}
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Employee()
    {
    }

    public Employee(int id,string fname,
             string lname)
    {
        this.EmployeeID = id;
        this.FirstName = fname;
        this.LastName = lname;
    }

    public void Deconstruct(out int id,
            out string fname,out string lname)
    {
        id = this.EmployeeID;
        fname = this.FirstName;
        lname = this.LastName;
    }
}

The Employee class has three public properties. One of the two constructors accept values that are then assigned to these three properties. The Deconstruct() method is more important to us. This is the method that does the deconstruction and its name must be Deconstruct().

The Deconstruct() method accepts certain output parameters. These parameters depend on the values that you wish to deconstruct. Inside, it assigns the corresponding property values to these output parameters.

To see the deconstruction in action you would write :

private Employee GetEmployee()
{
  Employee emp = new Employee(1, "Nancy", "Davolio");
  return emp;
}

(int id, string fname, string lname) = GetEmployee();
MessageBox.Show($"{id} - {fname} - {lname}");

The GetEmployee() method simply creates a new Employee object and returns it to the caller. Notice how the calling code deconstructs the Employee object. This is when the Deconstruct() method that you wrote earlier gets called. You can use id, fname and lname variables as usual.

5. Out variables

In the earlier versions of C# using output parameters required that you declared the necessary variables first and then pass them to a method using out keyword. In C# 7.0 you can simplify your code by doing both of these tasks at one go. This feature is called out variables. Suppose you have a simple method that takes two output parameters :

private void SetOutVariables(out string a,out string b)
{
    a = "Hello";
    b = "World!";
}

Inside, the SetOutVariables() method simply assigns certain string values to a and b. To call SetOutVariables() you would do the following :

SetOutVariables(out string s1, out string s2);
MessageBox.Show(s1 + " " + s2);

As you can see, the s1 and s2 variables are declared and passed while calling the method itself. You can then access s1 and s2 just like any other variables. If you are not interested in all the output parameter values you can skip some using the following syntax :

SetOutVariables(out string s1, out _);
MessageBox.Show(s1); 

Using the underscore character you can ignore an output value.

6. Digital separators and binary literals

A digital separator allows you to separate digits of any number for the sake of better readability. Consider the following code :

var i = 123456789;
var j = 123_456_789;

The first line is an ordinary variable declaration. The second line uses digital separator (the underscore character) to separate digits of a number. This separation is purely for the sake of readability.

In the older versions of C# numbers could be represented as decimal or hexadecimal values. In C# 7.0 you can also write numbers in binary form. See the following code :

int i = 0b101000;
MessageBox.Show(i.ToString());

The above code stores number 40 in an integer variable using its binary representation 101000. The prefix of 0b or 0B indicate that its a binary literal. Of course, when you output the value of i it's displayed as 40 and not in it binary format.

7. Throw expressions

In C# 7.0 you can throw exceptions directly from expressions. The following example will show you how :

string s = (DateTime.Now.Day > 20 ? "Month end" : 
throw new Exception("Too early!"));

The above statement directly throws an exception if month day is less than 20.

There is more - ref returns and locals, enhancements to expression bodied members and a few others. You may read more details here.

That's it for now ! Keep coding !!


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Meditation and Mindfulness to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 24 March 2017


Tags : .NET Framework C# Visual Studio Programming Languages