C# - What's new in C# 7.0?

You will need Visual Studio 2017 or higher. (Released March 2017). .NET Framework. 4.7.



1) out variables

out variables can now be declared in the caller argument list.


  // old syntax
  private void Test1()
  {
      // out variable must be declared prior to use
      int age;
      GetAge(out age);
      Console.WriteLine($"Your age is {age}");
  }
  
  // new syntax
  private void Test1()
  {
      // out variable can be declared in the argument list
      GetAge(out int age);
      Console.WriteLine($"Your age is {age}");
  }
  
  private void GetAge(out int age)
  {
      age = 20;
  }
  

2) tuples

Tuples now have full language support. No need to use System.Tuple.


  private void PrintWeather()
  {
      var w = GetWeather();
      Console.WriteLine("{0}, high temp {1}, low temp {2}", w.Item1, w.Item2, w.Item3);
  }
  
   // This is the new tuple - System.ValueTuple
  private (string, int, int) GetWeather()
  {
      var w = ("Rain", 74, 55);
      return w;
  }
  
  // This is the old tuple - using Sytem.Tuple
  private Tuple<string,int,int> GetWeather()
  {
      var w = Tuple.Create("Rain", 74, 55);
      return w;
  }
  
The new tuples:
  • Are value types
  • Support named Fields

  private void PrintWeather()
  {
      // Using named fields
      var w = GetWeather();
      Console.WriteLine("{0}, high temp {1}, low temp {2}", w.Forecast, w.High, w.Low);
  
      // deconstructing the tuple
      (string weather, int high, int low) = GetWeather();
      Console.WriteLine("{0}, high temp {1}, low temp {2}", weather, high, low);
  }
  
  // Using named fields
  private (string Forecast, int High, int Low) GetWeather()
  {
      var w = (Forecast: "Rain", High: 74, Low: 55);
      // or
      w = ("Rain", 74, 55);
      return w;
  }
  

3) pattern matching


3a) is expression with pattern variables


Pre C# 7, you would need to check for type, declare a variable, and then cast to assign.


  public static int SumValues(IEnumerable<object> values)
  {
      var sum = 0;
      foreach(var item in values)
      {
            if (item is int)
            {
                var val = (int)item;
                sum += val;
            }
      }
      return sum;
  }
  

The new C# 7 syntax lets you check, declare, and assign, in one line.


  public static int SumValues(IEnumerable<object> values)
  {
      var sum = 0;
      foreach(var item in values)
      {
            if (item is int val)
                sum += val;
      }
      return sum;
  }
  

3) pattern matching


3b) switch statement with pattern variable


You can now switch on an object type, or type with condition.


  public void TestObject(object obj)
  {
    switch(obj)
    {
        case System.Drawing.Point p:
            break;
        case System.Drawing.Rectangle r when (r.IsEmpty):
            break;
        case System.Drawing.Rectangle r:
            break;
    }
  }
  

Prior to C# 7.0, you would need to write:


  public void TestObject(object obj)
  {
      if(obj is Point)
      {
          var p = (Point)obj;
      }
      else if(obj is Rectangle)
      {
          var r = (Rectangle)obj;
      }
  }
  

4) ref locals and ref return


Lets you return a reference to a value type. Similar to the C++ operator & (address of).


  static void Main()
  {
      var m = new Math();
  
      // this is a ref local
      ref double pi = ref m.GetPi();
  
      pi = 3; // change PI
      pi = m.GetPi(); // re-get PI
  
      Console.WriteLine("PI is {0}", pi);
  }
  
  class Math
  {
      private double _pi = 3.14159265359;
      public ref double GetPi()
      {
          // this is a ref return
          return ref _pi;
      }
  }
  
  PI is 3

In this example, we were able to change the value of the double returned by Math.GetPi() because we returned the value by reference.

5) local functions


  void Main()
  {
      void Log(string message) { Console.WriteLine("Main() - {0}", message); }
  
      Log("begin");
      Log("end");
  }
  
  Test1() - begin
  Test1() - end
  

6) more expression-bodied members


C# 6 introduced expression-bodied members.


  public override ToString() => "To be or not to be.";
  
C# 7 extends expression-bodied member support to:
  • constructors
  • finalizers
  • get and set accessors on properties and indexers

  class MyClass1
  {
      int _count;
 
      // constructor
      public MyClass1(int count) => _count = count;
 
      // finalizer
      ~MyClass1() => Console.WriteLine("finalizer called");
 
      // get/set accessors
      public int Count
      {
          get => _count;
          set => _count = value;
      }
  }
  

7) throw expressions

Since throw is a statement, and not an expression, it can't be used in the middle of an expression. Example below:


  void throw_expression()
  {
      var c = new MyClass1();
      c.Message = "Hello";
  }
  
  class MyClass1
  {
      string _message;
      public string Message
      {
          get { return _message; }
          set { _message = value==null ? throw new ArgumentNullException("Message") : _message = value; }
      }
  }
  

Under C# 6, this fails with the error:


  Invalid expression term 'throw'
  

In C# 7, throw is an expression, and the above syntax is valid.

8) generalized async return types


Any method declared as async, must have one of the following return types:

  • void - can not be used with await
  • Task - can be used with await. no return value.
  • Task<T> - can be used with await. returns a result of type T.

Aside from void, these are all reference types.

C# 7 allows a value type to be returned using the ValueTask type.


  public async ValueTask<int> DoSomethingAsync()
  {
      return 1;
  }
  

ValueTask<TResult> is recommended over Task<TResult> when the task is expected to complete synchronously and be called frequently.

9) numeric literal syntax improvements


Support for binary syntax and digit separators.


  // prefix with 0b for binary
  const int BitMask3 = 0b00000011;
  
  // use underscore as a digit separator
  const long OneHundredBillion = 100_000_000_000; // More readable than 100000000000
  

Ads by Google


Ask a question, send a comment, or report a problem - click here to contact me.

© Richard McGrath