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.







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.

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

Local Functions or Nested Functions Binary Literals Digit Separators Pattern matching ref returns and ref Locals Tuples (Tuples Enhancement) Throw Expressions Expression Bodied Members (methods, properties, constructors, destructors, getters, setters, indexers, operators, Main method) Out variables (enhancement for out variables) Deconstruction Discards Generalized async return types

Async Main: Main Method returning Task Infer Tuple Element Names Default Literal Expressions and Type Inference Pattern Matching with Generics

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

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

‘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.

Code Snippet

static void Main(string[] args) { int x, y =0; DoSomething(out x, ref y); WriteLine($ "x: {x}

y: {y}" ); } public static void DoSomething(out int x, ref int y) { x = 10; y = 20; }

Output

x: 10

y: 20





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





static void Main(string[] args) { int x =20; DoSomething(ref x); WriteLine($ "Value of x is :{x}" ); } public static void DoSomething(ref int x) { WriteLine($ "Value of x is :{x}" ); x += 10; }

Output

Value of x is :20

Value of x is :30





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





Code Snippet 1

static void Main(string[] args) { int x = 20; DoSomething(out x); WriteLine($ "Value of x is :{x}" ); } public static void DoSomething(out int x) { x += 10; }

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

Have a look at the below code snippet:

static void Main(string[] args) { int a = 20, b = 30, c=0; Write($ "Sum of {a} and {b} is: " ); Add(a, b, ref c); WriteLine($ "{c}" ); } public static void Add(ref readonly int x, ref readonly int y, ref int z) { z=x + y + z; }

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

static void Main(string[] args) { int a = 20, b = 30, c = 10; Write($ "Sum of {a} and {b}is: " ); Add(a, b, out c); WriteLine($ "{c}" ); } public static void Add(ref readonly int x, ref readonly int y, out int result) { result = x + y; }

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.





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

using System; using static System.Console; namespace PrivateProtectedExample { class Program { static void Main(string[] args) { } } public class Employee { public int Id { get; set; } protected int Name { get; set; } internal DateTime DOB { get; set; } private Decimal Salary { get; set; } protected internal int DepatmentId { get; set; } private protected string ProjectName { get; set; } } class SubEmployee : Employee { void Print() { SubEmployee employee = new SubEmployee(); WriteLine(employee.ProjectName); } } }

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.









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.

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

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.

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.

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





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.

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.

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.





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”.

Have a look at the below code snippet

static void Main(string[] args) { long result = Sum(10, num2nd:20); } public static long Sum( int num1st, int num2nd= default , int num3rd= default ) { return num1st + num2nd + num3rd; }

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.





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”.





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







It opens the “Advanced Build Settings” window.

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





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.

Also recommended: