C# 7.2 New Features With Visual Studio 2017

This article explains the new features of C# 7.2. It covers ‘ref readonly’, ‘private protected’ access modifier, Digit Separator After Base Specifier (Leading Digit Separator) and non-trailing named arguments.

C#

This article is my third article on the topic C# 7.x new features. If you missed my previous articles, then I recommend you to go through the below-provided links.

C# 7.0 & C# 7.1 New Features: Part Two

In previous 2 articles, I have covered following features of C# 7.0 & C# 7.1

C# 7.0
  1. Local Functions or Nested Functions
  2. Binary Literals
  3. Digit Separators
  4. Pattern matching
  5. ref returns and ref Locals
  6. Tuples (Tuples Enhancement)
  7. Throw Expressions
  8. Expression Bodied Members (methods, properties, constructors, destructors, getters, setters, indexers, operators, Main method)
  9. Out variables (enhancement for out variables)
  10. Deconstruction
  11. Discards
  12. Generalized async return types
C# 7.1
  1. Async Main: Main Method returning Task
  2. Infer Tuple Element Names
  3. Default Literal Expressions and Type Inference
  4. Pattern Matching with Generics
Topics Covered in this article

I am going to cover the following features of C# 7.2 in this article

  1. ‘ref readonly’
  2. ‘private protected’ Access Modifier
  3. Digit Separator After Base Specifier (Leading Digit Separator)
  4. Non-trailing named arguments
‘ref readonly’

 ‘ref readonly’ is a new feature in C# added with C# 7.2. It behaves opposite to out variable. To understand ‘ref readonly’  you must be aware of the existing behaviour of ‘ref’ and ‘out’. If you want to deep dive into the current behavior, then please visit here.

Existing Behavior: ref and out both are passed as reference.

Code Snippet

  1. static void Main(string[] args)  
  2.         {  
  3.             int x, y =0;  
  4.             DoSomething(out x, ref y);  
  5.             WriteLine($"x: {x} \ny: {y}");  
  6.         }  
  7.   
  8.         public static void DoSomething(out int x, ref int y)  
  9.         {  
  10.             x = 10;  
  11.             y = 20;  
  12.         }  

Output

x: 10

y: 20

C#

Existing Behaviour Pass a variable as a reference with read-write (input-output) option.

A variable passed with ref keyword can be used for input and output purposes as well.

C# 

  1. static void Main(string[] args)  
  2. {  
  3.     int x =20;  
  4.     DoSomething(ref x);  
  5.     WriteLine($"Value of x is :{x}");  
  6. }         
  7. public static void DoSomething(ref int x)  
  8. {  
  9.     WriteLine($"Value of x is :{x}");  
  10.     x += 10;  
  11. }  

Output

Value of x is :20

Value of x is :30

C#

Existing Behaviour Pass a variable as a reference with write-only (output) option.

‘out’ variable is only for output not for input. It means we cannot pass a variable value as input using out parameter.

C#

Code Snippet 1

  1. static void Main(string[] args)  
  2. {  
  3.     int x = 20;  
  4.     DoSomething(out x);  
  5.     WriteLine($"Value of x is :{x}");  
  6. }  
  7. public static void DoSomething(out int x)  
  8. {  
  9.     //Use of unassigned out parameter 'x'  
  10.     x += 10;  
  11. }  

Compiler Error: “Use of unassigned out parameter 'x'”

New Behaviour in C# 7.2: Pass a variable as a reference with read-only (input) option.

Have a look at the below code snippet:

  1. static void Main(string[] args)  
  2. {  
  3.   
  4.     int a = 20, b = 30, c=0;              
  5.     Write($"Sum of {a} and {b} is: ");  
  6.     Add(a, b, ref c);  
  7.     WriteLine($"{c}");  
  8. }  
  9. public static void Add(ref readonly int x, ref readonly int y, ref int z)  
  10. {  
  11.     z=x + y + z;  
  12. }  

You can see that the variable ‘x’ and ‘y’ has been passed as ‘ref readonly’ whereas ‘z’ has been passed as ref.

If we modify the above code snippet to specify my intent then it can be written as

  1. static void Main(string[] args)  
  2. {  
  3.   
  4.     int a = 20, b = 30, c = 10;  
  5.     Write($"Sum of {a} and {b}is: ");  
  6.     Add(a, b, out c);  
  7.     WriteLine($"{c}");  
  8. }  
  9. public static void Add(ref readonly int x, ref readonly int y, out int result)  
  10. {  
  11.     result = x + y;  
  12. }  

Now the variable ‘x’ and ‘y’ is readonly and variable ‘result’ is write-only. If we try to alter its behavior, then it gives compile time error. Following is a screenshot for the same.

C#

private protected
C#

In C# 7.2 a new access modifier ‘private protected’ has been added. Thus, we have total 6 access modifier in C# 7.2.

  • public
  • protected
  • internal
  • private
  • protected internal
  • private protected

However, all the above 6 access modifiers cannot be used everywhere there are some rules for their usage. Please visit here for more details about access modifiers.

‘private protected’ is accessible inside the type in which it has been declared and within the same assembly by types derived from the containing type.

Let’s try to understand the same with some examples

  1. using System;  
  2. using static System.Console;  
  3.   
  4. namespace PrivateProtectedExample  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.               
  11.         }  
  12.     }  
  13.   
  14.     public class Employee  
  15.     {  
  16.         public int Id { get; set; }  
  17.         protected int Name { get; set; }  
  18.         internal DateTime DOB { get; set; }  
  19.         private Decimal Salary { get; set; }  
  20.         protected internal int DepatmentId { get; set; }  
  21.         private protected string ProjectName { get; set; }  
  22.     }  
  23.   
  24.     class SubEmployee : Employee  
  25.     {  
  26.         void Print()  
  27.         {  
  28.             SubEmployee employee = new SubEmployee();  
  29.             WriteLine(employee.ProjectName);  
  30.         }  
  31.     }  
  32. }  

You can see that it is accessible by child class which is contained inside the same assembly. Now try to access it outside the assembly with inheritance or within the assembly without inheritance.

private protected member is inaccessible outside the assembly for the child class.

C#

private protected member is inaccessible inside the assembly for non-inherited class.

C#

Thus, it proves the above statement ‘private protected’ is accessible inside the type in which it has been declared and within the same assembly by types derived from the containing type.

Digit Separator After Base Specifier (Leading Digit Separator)

overview of numeric literal enhancement done in C# 7.0

In C# 7.0 following enhancements has been done for numeric literals:

Binary literal

Before C# 7.0 two types of notations were supported in C# - decimal literal and hexadecimal literal. In C# 7.0 binary literal has been introduced.

Decimal Literal

int length = 50;

Hexadecimal Literal 

int number = 0X3E8;
or
int number = 0x3E8;

Binary Literal

int fifty = 0B110010;

or

int fifty = 0b110010;

So, you can see that when you are not using any prefix with integer data type, then it is by default denoting a number in the decimal system. Whereas for a hexadecimal number, we need to use prefix “0X” or “0x” (you can use either small ‘x’ or capital ‘X’) and prefix “0B” or “0b” for binary literals.

Digit Separator

In C# a digit separator ‘_’ (underscore character) can be used. We can use any number of underscore characters. So, fifty can be written like

int fifty = 0B11_00____10;

note

the above statement is just for an explanation but in general we use only one underscore character as the digit separator.

Enhancement done in C# 7.1 for numeric literals (Leading Digit Separator)

If you take the example of above statement and try to write like below code snippet

int fifty = 0B_11_00_10;

Then it will give compilation error in C# 7.0

C#

However, it gets compiled successfully in C# 7.2 because C# 7.2 supports Leading Digit Separator which is also known as digit separator after base specifier.

Non-trailing named arguments

Till C# 7.1 there was a restriction that we cannot use named arguments before any unnamed parameters. Let’s try to understand the same with a small example.

Overview of Named Parameters:

In C# 4.0 a new type of argument is introduced known as a named parameter. Using this feature, we can specify the value of a parameter by parameter name regardless of its ordering in the method. I am using a simple method to explain it. Have a look at the following screenshot.

C#
However, all the named parameters must appear after fixed arguments. If we provide any fixed argument after named argument then it will give the following compile time error “Named argument specifications must appear after all fixed arguments have been specified”.

Non-Trailing named arguments in C# 7.2

Have a look at the below code snippet

  1. static void Main(string[] args)  
  2. {  
  3.     long result = Sum(10, num2nd:20);  
  4. }  
  5.   
  6. public static long Sum(int num1st, int  num2nd=defaultint num3rd=default)  
  7. {  
  8.     return num1st + num2nd + num3rd;  
  9. }  

It will get compiled successfully. You can see that I am passing only 2 parameters as I can omit optional parameters. Now pass the 3rd parameter as well.

C#

You can see in the above screenshot that it is saying that “Named argument specifications must appear after all fixed arguments have been specified”.

Now change C# language version to C# 7.2 and re-compile it. It will get compiled successfully. 

Thus, in C# 7.2 it is not mandatory to pass named arguments as trailing arguments as far as the ordering of the variable is correct.

In this article, I have shown you many times that if we need to use upper language version, then you just need to click on “Quick Action” light bulb. It will suggest you use a newer version of C#, and by just clicking on it you can upgrade to latest C# version, e.g. C# 7.2.

However, if you are not aware of how you can change C# language version in Visual Studio 2017, then please follow the below steps:

Open Solution Explorer inside Visual Studio 2017

Select the project and right click on it to open the context menu and select “Properties”.

C#

Inside the Project, property window clicks on “Build Tab” and then click on “Advanced…” button.

C#

It opens the “Advanced Build Settings” window.

Inside the “Advanced Build Settings” window you can select any available C# language version.

C#

So far  we have gone through the four essential new features of C# 7.2 which are ‘ref readonly’, ‘private protected’ access modifier, Digit Separator After Base Specifier (Leading Digit Separator) and Non-trailing named arguments. Apart from these four features, some more features have been added in C# 7.2. However, I have covered only those features which are finalized and supporting with Visual Studio 2017. I will come with some more new feature of C# 7.2 & C# 7.3 once their development completed and support provided in Visual Studio.