Friday, 20 May 2016

Essential C# 6 Features You Need to Know!

With the final version of C# 6 having been released, we can seen that a lot of syntax changes have occurred since its inception. Because of this, I’ve noticed that most of the blog posts currently on the internet don’t work anymore or are too vague about how they implemented a feature.
I thought it would be useful to make a list of the most essential C# 6 features with simple code examples that would make it both easy to understand and simple to copy/paste a sample into a new console app to try it. Let’s jump in.
The complete Visual Studio 2015 Console Application with all of the demos shown in this article can be found on Github.

Static Using Syntax

In previous versions of C#, if we wanted to print something to the Console, we would write the following line of code:
using System;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
With C# 6, you can now add the using static qualifier and reference the WriteLine method by itself as shown below:
using static System.Console;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Hello World!");
        }
    }
}
This also works for classes that we’ve created ourselves. Take a look at the following example.
using static System.Console;
using static CSharpSix.YetAnotherClass;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Hello World!");
            HelloBack();
        }
    }
    static class YetAnotherClass
    {
        public static void HelloBack()
        {
            WriteLine("Hello Computer!");
        }
    }
}
Since we declared YetAnotherClass with the static keyword, we can run the method by just calling the method name. The output for this sample would be :
Hello World!
Hello Computer!

Auto-Property Initializers

In the past, we may have created our properties with a getter and setter and initialized our constructor with the value as shown below.
using System;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer cust = new Customer();
            Console.WriteLine(cust.customerID);
            Console.ReadLine();
        }
    }

    public class Customer
    {
        public Customer()
        {
            customerID = Guid.NewGuid();
        }

        public Guid customerID { get; set; }
    }

}
We can now modify the Customer class and populate the property calledcustomerID with inline initialization in C# 6.
using System;
using static System.Console;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer cust = new Customer();
            WriteLine(cust.customerID);
            ReadLine();
        }
    }

    public class Customer
    {
        public Guid customerID { get; set; } = Guid.NewGuid();
    }

}
The output for this sample will be a random guid generated by the system.

Dictionary Initializers

In C# 5, you would initialize the Dictionary with a {"Key", "Value"} syntax, as in the example below.
using System.Collections.Generic;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            var stars = new Dictionary<string, string> ()
            {
                 { "Michael Jordon", "Basketball" },
                 { "Peyton Manning", "Football" },
                 { "Babe Ruth", "Baseball" }
            };

            foreach (KeyValuePair<string, string> keyValuePair in stars)
            {
                Console.WriteLine(keyValuePair.Key + ": " +
                keyValuePair.Value + "\n");
            }

            Console.ReadLine();
        }
    }
}
In C# 6, you just place the key between two square brackets ["Key"] and then set the value of the key ["Key"] = "value". This syntax is cleaner, in my opinion, and reduces the amount of errors that the old way produced.
using System.Collections.Generic;
using static System.Console;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            var stars = new Dictionary<string, string> ()
            {
                ["Michael Jordan"] = "Basketball",
                ["Peyton Manning"] = "Football",
                ["Babe Ruth"] = "Baseball"
            };

            foreach (KeyValuePair<string, string> keyValuePair in stars)
            {
                WriteLine(keyValuePair.Key + ": " +
                keyValuePair.Value + "\n");
            }

            ReadLine();
        }
    }
}

String Interpolation

Prior to C# 6.0, we typically concatenated two or more strings together with one of the following methods:
using System;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            string firstName = "Michael";
            string lastName = "Crump";

            Console.WriteLine("Name : " + firstName + " " + lastName);
            Console.WriteLine("Name : {0} {1}", firstName, lastName);

            Console.ReadLine();
        }
    }
}
In C# 6.0, we have a cleaner way to format a string by writing our own arguments instead of referring to them as placeholders. Just make sure you use the $ before the start of the string.
using static System.Console;

namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            string firstName = "Michael";
            string lastName = "Crump";

            WriteLine($"{firstName} {lastName} is my name!");

            ReadLine();
        }
    }
}
The output for this example is :
Michael Crump is my name!

nameOf Expression

This feature was designed due to the large amounts of code that many enterprise level applications have. One common error is using hard-coded name strings with an error message. Due to the nature of the apps in general and re-factoring, sometimes the names change and the string representation is left alone – thus breaking the app. Here is one example.
using System;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {

            DoSomething("Hi");
            ReadLine();
        }

        public static void DoSomething(string name)
        {
            if (name == null) throw new Exception("Name is null");
        }
    }
}
This code will not produce an error as expected as the string is equal to null.
What happens if someone changes the name variable to newName? Since we hard-coded the “Name is null” error, that is what will appear to the end-user. We would rather it now say, “newName is null”, but the compiler cannot recognize this mistake.
In C# 6.0, we can refactor our code to remove the string literals and use the nameof expression.
using System;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {

            DoSomething("Hi");
            ReadLine();
        }

        public static void DoSomething(string newName)
        {
            if (newName == null) throw new Exception(nameof(newName) + " is null");
        }
    }
}
This results in cleaner code and type safety when retrieving member names. In this case, if we removed the newName variable and gave it a new name then the compiler would catch the error before the program was executed.

Expression Bodied Function & Property

Functions and properties in lambda expressions save you from defining your function and property statement block. Take note of theMultipleNumbers function below:
using static System.Console;

namespace CSharpSix
{
    class Program
    {
        private static double MultiplyNumbers(double num1, double num2) => num1 * num2;

        static void Main(string[] args)
        {
            double num1 = 5;
            double num2 = 10;

            WriteLine(MultiplyNumbers(num1, num2));
            ReadLine();
        }
    }
}
The result of the above program would be 50.
This shorthand notation may be confusing at first, but I think after you get used to it then can make your program much more readable.

Exception Filters

Exception filters have been supported in Visual Basic, but are new to the C# compiler. They allow you to specify a condition for a catch block. We typically used the following in C# 5:
using System;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            var httpStatusCode = 404;
            Write("HTTP Error: ");

            try
            {
                throw new Exception(httpStatusCode.ToString());
            }
            catch (Exception ex)
            {
                if (ex.Message.Equals("500"))
                    Write("Bad Request");
                else if (ex.Message.Equals("401"))
                    Write("Unauthorized");
                else if (ex.Message.Equals("402"))
                    Write("Payment Required");
                else if (ex.Message.Equals("403"))
                    Write("Forbidden");
                else if (ex.Message.Equals("404"))
                    Write("Not Found");
            }

            ReadLine();
        }
    }
}
Rather than entering the catch block and checking to see which condition met our exception, we can now decide if we even want to enter the specific catch block.
using System;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            var httpStatusCode = 404;
            Write("HTTP Error: ");

            try
            {
                throw new Exception(httpStatusCode.ToString());
            }
            catch (Exception ex) when (ex.Message.Equals("400"))
            {
                Write("Bad Request");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("401"))
            {
                Write("Unauthorized");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("402"))
            {
                Write("Payment Required");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("403"))
            {
                Write("Forbidden");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("404"))
            {
                Write("Not Found");
                ReadLine();
            }

            ReadLine();
        }
    }
}

Await in a Catch and Finally Block

Brand new to C# 6, you can write asynchronous code inside in a catch/finally block. This will help developers as they often need to log exceptions to a file or database without blocking the current thread. Here is an example of how one would work:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => GetPage());
            ReadLine();
        }

        private async static Task GetPage()
        {
            HttpClient client = new HttpClient();
            try
            {
                var result = await client.GetStringAsync("http://www.telerik.com");
                WriteLine(result);
            }
            catch (Exception exception)
            {
                try
                {
                    //This asynchronous request will run if the first request failed. 
                    var result = await client.GetStringAsync("http://www.progress.com");
                    WriteLine(result);
                }
                catch
                {
                    WriteLine("Entered Catch Block");
                }
                finally
                {
                    WriteLine("Entered Finally Block");
                }
            }
        }
    }
}

Null Conditional Operator

Every developer hates NullReferenceException errors! This is the typical code one would check prior to C# 6.0.
using System;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            if (person.Name == String.Empty)
            {
                person = null;
            }

            WriteLine(person != null ? person.Name : "Field is null.");

            ReadLine();
        }
    }

    public class Person
    {
        public string Name { get; set; } = "";
    }
}
This returns “Field is null”. If we enter some data into name, then the console prints out whatever is contained in the name.
Using C# 6.0, we can use ?. to check if an instance is null or not. The code listing below will print the person.Name field if one is supplied or will print “Field is null” if one isn’t supplied.
using System;
using static System.Console;


namespace CSharpSix
{
    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            if (person.Name == String.Empty)
            {
                person = null;
            }

            WriteLine(person?.Name ?? "Field is null.");

            ReadLine();
        }
    }

    public class Person
    {
        public string Name { get; set; } = "";
    }
}

Wrap-Up

Thankfully C# 6.0 is final and can be used in production environments now. I wasn’t able to touch on every feature, but you can always referenceMSDN for more info.
I would also encourage you to check out what is included in Visual Studio 2015 while you are there. In case you are wondering, all of our UI components included in DevCraft are fully functional with Visual Studio 2015 and hopefully you can use some of the cool new C# 6 features that I wrote about today.
So did I miss a cool feature or do you have a better way to do something? Sounds off in the comments below!

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...