C#7.2

One theme for this release is working more efficiently with value types by avoiding unnecessary copies or allocations.

PRIVATE PROTECTED

"private protected" is now a valid modifier. It's equivalent to protected, except that it can only be accessed inside the current assembly.

class BaseClass           { private protected void Foo() {} }
class Derived : BaseClass { void Bar() => Foo();            }

'IN' KEYWORD

We can now place the "in" keyword before parameters to prevent them from being modified. This is particularly useful with structs, because the compiler avoids the overhead of having to copy the value

void Foo (in string s, in int x, in Point point)
{
  // s = "new";  // error
 // x++;        // error
 // point.X++;  // error
}

void TestFoo() => Foo ("hello", 123, new Point (2, 3));

Note that you don't specify the 'in' modifier when calling the method

readonly struct

Structs can now be made immutable by including the 'readonly' modifier in the declaration.

Readonly structs improve efficiency by allowing the compiler to make additional optimizations

readonly struct Point
{
 public readonly int X, Y;    // All fields must be readonly

 public Point (int x, int y)
 {
  X = x;
  Y = y;
 }
}

ref struct

The ref struct declaration, to indicate that a struct type accesses managed memory directly and must always be stack allocated.

A ref struct cannot be a member of a class or used in other locations where it may be allocated on the heap.

ref struct StackOnlyPoint
{
  public int X, Y;
}

void Main()
{
 var point = new StackOnlyPoint { X = 1, Y = 2 };
  
 object o = point; //throws compile time error.
                  // Reason: Because we're trying to box the ref struct
}

ref readonly

The ref readonly modifier on method returns, to indicate that a method returns its value by reference but doesn't allow writes to that object.

Conditional ref expressions

The conditional expression may produce a ref result instead of a value result

ref var r = ref (arr != null ? ref arr[0] : ref otherArr[0]);

The variable r is a reference to the first value in either arr or otherArr.

Non-trailing named arguments

Named arguments can be followed by positional arguments.

Before 7.2, Named arguments, when used with positional arguments, are valid as long as they're not followed by any positional arguments. Example:

PrintOrderDetails("Gift Shop", 31, productName: "Red Mug"); 

Starting with 7.2, Named arguments, when used with positional arguments are also valid when they're used in the correct position.

In the example below, the parameter orderNum is in the correct position but isn't explicitly named.

PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug"); 

However, out-of-order named arguments are invalid if they're followed by positional arguments.

// This generates CS1738: Named argument specifications must appear after all fixed arguments have been specified.

PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");