A Quick Introduction to C# 7 new features

In the recent developer event connect(), Microsoft has announced Visual Studio 2017 RC. Visual Studio 2017 RC release notes described you all their most up-to-date feature innovations and enhancements. With release of VS 15 preview 4, C# 7 is introduced with lot's of improvements and features.
In this article we will see brief introduction of
  • Tuples
  • Out variables
  • Ref return and Ref local
  • Local functions
  • Throw exceptions
  • Pattern matching
  • Digit separators
  • Binary literals
  • Extended expression bodied members list
Note that C# 7 is still in development and all features are subject to change at any time.

Tuples

The most common reason to use Tuples is to have multi results. Tuples are defined on the fly instead of pre creating any POCO classes. C# 7 supports multiple value returns.  the compiler will use the new ValueTuple struct.
public (int x, int y) Compute(){
    return (1, 2);
}  
Defined name on the method signature will be used directly if the method returns a single variable.
var result = Compute();
> result.x
> 1
> result.y
> 2
or use traditional approach
var result = Compute();
> result.Item1
> 1
> result.Item2
> 2

Out variables

The out keyword causes arguments to be passed by reference. We need to declare variable (initializing is optional) before use it. You have to declare them with specific type instead of var.
public void PrintHeight()
{
    int height; // need to declare it first.
    CalculateHeight(out height);
    WriteLine($"({height})");
}
C# 7.0 has direct support to use them in at the time when we are passing an argument.
public void PrintHeight()
{
    CalculateHeight(out int height);
    WriteLine($"({height})");
}
So, things are going to be easy while using try parse.

Ref Return and Ref Local

Previously, Ref keyword is used to pass parameters as reference. Once the parameter value is changes in the method, calling method will be reflected too. We must declare and initialize the variable before passing it with ref keyword.
int val1 = 0;
Example1(ref val1);
Console.WriteLine(val1); 

void Example1(ref int value)
{
   value = 1;
}

Output
> 1
In C# 7, Just like you can pass parameters by reference, you can now return them by reference, and also store them by reference in local variables.
public ref int FindBrand(int index, string[] brands)
{
    if(brands.length > 0)
    return ref brands[index];
    
    throw new IndexOutOfRangeException($"{nameof(index)} not found");
}

string[] brands = { "Nike", "Puma", "Levi's", "UCB", "Addidas" }; 
ref string brand = ref FindBrand(2, brands); // returns Puma
brand = "Reebok"; // replace Puma with Reebok
WriteLine(brands[2]); // print Reebok

Local functions

Some time helper method can only help to specific method only. You can define such functions within a scope of that method as a local function. Local functions are not available outside of it and have access all local variables, async/await and lambda syntax.
public void Foo(int x)
{
    return Localfunction();
    
    int Localfunction()
    {
        return x;
    }
}
Local functions make recursions more easy and as it don't require allocated delegates to hold them, it helps to reduce memory usage.

Throw expressions

C# 7.0 allows throw an exception in middle of the expression.
class Person
{
    public string Name { get; }
    public Person(string name) => Name = name ?? throw new ArgumentNullException(name);
    public string GetFirstName()
    {
        var parts = Name.Split(" ");
        return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException("No name!");
    }
    public string GetLastName() => throw new NotImplementedException();
}
In our example, we are throwing two exceptions directly from the expression. When the Constructor sets up the value of Name, if the name parameter is null then it will throw ArgumentNullException. In another case, the exception is used in ternary operator. If parts array's length is less than zero then it will throw InvalidOperationException.

Pattern Matching

C# 7 supports pattern matching for is and switch expression to extend the existing pattern matching capabilities.

Is Expression

The is operator is used to extend the pattern matching capabilities. Is operator can be used to declare new variables and assign values.
void Find( object obj)
{
     //following null is constant pattern
     if (obj is null)  return;
    
     //datatype pattern, string is datatype that can be check directly     
     if (obj  is  string st)
       //code goes here
     else
       return; 
}
First if statement is example of constant pattern when we matching obj with null. Second if statement string st is declared within expression and can be used within the scope if not even in else.

Switch Expression

Switch statement is already a part of C#, in C# 7 switch statement has been extended with pattern matching. The Switch statement is slightly different than is expression, when you declare the type and variable at the beginning of the case expression.
public static int DiceSum4(IEnumerable<object> values)
{
    var sum = 0;
    foreach (var item in values)
    {
        switch (item)
        {
            case 0:
                break;
            case int val:
                sum += val;
                break;
            case IEnumerable<object> subList when subList.Any():
                sum += DiceSum4(subList);
                break;
            case IEnumerable<object> subList:
                break;
            case null:
                break;
            default:
                throw new InvalidOperationException("unknown item type");
        }
    }
    return sum;
}
The code above adds cases for 0 as a special case of int, and null as a special case when there is no input. This same behavior enables the special case for an empty input sequence. You can see that the case for an IEnumerable item that has elements must appear before the general IEnumerable case. The default case is always evaluated last, regardless of the order it appears in the source.

Digit separators

C# 7 consider _ (underscore) as a digit separator. More than one digit separator allows at any place to improve readability.
var d = 123_456;
var x = 0xAB_CD_EF;
The _ is allowed in decimals as well as exponents. The separators have no semantic impact - they are simply ignored.

Binary literals

C# 7 introduces binary literals to use bit patterns directly instead of having to know hexadecimal notation.
var b = 0b1010_1011_1100_1101_1110_1111;
This can be useful for working with binary flags.
[Flags]
public enum Tasks
{
    // decimal hex bit shifting
    Save = 1,           // = 0x01 = 1 << 0
    Publish = 2,         // = 0x02 = 1 << 1
    SaveAndPublish = 4,    // = 0x04 = 1 << 2
}
With binary literals, it is more obvious which bits are set, and using them does not require understanding hexadecimal numbers and bitwise arithmetic:
[Flags]
public enum Tasks
{
    Save = 0b00000001,
    Publish = 0b00000010,  
    SaveAndPublish = 0b00000100
}

Extended expression bodied members list

Expression-bodied members feature is introduced in C# 6, are now allowed on accessors, constructors and finalizers.
class Person
{
    private static ConcurrentDictionary<int, string> names = new ConcurrentDictionary<int, string>();
    private int id = GetId();

    public Person(string name) => names.TryAdd(id, name); // constructors
    ~Person() => names.TryRemove(id, out *);              // destructors
    public string Name
    {
        get => names[id];                                 // getters
        set => names[id] = value;                         // setters
    }
}
Example describes everything about extended expression bodied members feature.

References