Written by 12:40 Basics of C#, Languages & Coding • One Comment

New Features of C# To Be Expected Soon

In April 2003, C# 1.2. was released. Ever since all the versions have had the only major version. Now, if what the official page of roslyn on github  says is true, versions 7.1.and 7.2 are under development.

To try version 7.1, it is necessary to install the preview Visual Studio. You can download it from the official site.

When you go to the solution properties, it is possible to select the language version you are using.

Next, I would like to share with you the new features of the language I liked.

Asynchronous Main (it is going to be released in version 7.1)

Nowadays, there are programs to be completely asynchronous. So far, Main could be void or int and contain arguments as a string array. Now, several new overloads will be added:

public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);

As CLR does not support asynchronous entrypoints, a compiler creates a boilerplate code. It means that it automatically inserts some additional code that allows void to be cast to Task. Here is a the that may be generated by the compiler:

async Task<int> Main(string[] args) {
    // your custom code 
}
// this method is generated behind the scenes automatically
int $GeneratedMain(string[] args) {
    return Main(args).GetAwaiter().GetResult();
}

Like many others, I have expected this functionality to appear in the 7th version of the language.

Default Literal (it is going to be released in version 7.1)

Both Visual Basic and C# have similar features. Still, there are certain differences in the languages. Say, C# has null, while VB.NET has Nothing. So, unlike null, Nothing can be converted to any system type, being a default value for this type. Sure null couldn’t be converted to a default value. However, the default value could be null.

There is the default(T) statement, which can be applied now.

Let’s consider how it can be used. Assume we have a method that accepts a string array as a parameter:

void SomeMethod(string[] args)
{
            
}

We can execute the method and pass a default value of the string array to it:

SomeMethod(default(string[]));

But why should we write default(string[]) if we can simply use default?

Starting from C# 7.1, you can use the default literal. What else can we do with it other than pass the default value to the method? For example, it can be used as a value for an optional parameter:

void SomeMethod(string[] args = default)
{
            
}

Or we can initialize a variable with the default value:

int i = default;

Additionally, we can check whether the current value is the default one:

int i = 1; 
if (i == default) { }   // the is operator cannot be used with default
if (i is default) { }     // 'as' can be only of the reference type

Readonly ref (it is going to be released in version 7.2)

When adding structures to methods as ‘by value’, copying objects take place, which requires resources. Sometimes, there is a need in adding only one value of the reference object. In this case, developers send a value using the reference (ref) to save memory and add comments that the value must not be modified. Very often, this is true in math operations with the vector and matrix objects.

The example is as follows:

 static Vector3 Add (ref readonly Vector3 v1, ref readonly Vector3 v2)
    {
        // This is not right!
        v1 = default(Vector3);

        // This is not right either!
        v1.X = 0;

        // This is not right as well!
        foo(ref v1.X);

        // And this is ok
        return new Vector3(v1.X +v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
    }

This function is still a prototype. However, I am sure that we need to use it. One of the suggested options is to use the keyword in instead of ref readonly.

static Vector3 Add (in Vector3 v1, in Vector3 v2)
   {
       return new Vector3(v1.X +v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
   }

It is better to use in as it is shorter than ref readonly.

Default interface methods (it is going to be released in version 8.0)

Imagine that there is a class or structure that implement the interface. They will be able to inherit the implementation of one method from the interface (!) or will have to implement their version of this method.

The concept of implementation in the interface sounds rather strange, although there are default interface methods in Java 8. So, C# developers want to have a similar functionality as well.

This functionality will allow an API writer to modify the method code for all the current interface implementations.

We will consider this on the particular example. Assume we have an interface where SomeMethod has the following implementation:

interface IA
{
 void SomeMethod() { WriteLine("SomeMethod of the IA interface is called"); }
}

Now, create a class, which implements the interface:

class C : IA { }

And create an instance of the interface:

IA i = new C();

Now, we can call SomeMethod:

i.SomeMethod(); // will display the following message "SomeMethod of the IA interface is called"

Optional tuple names (to be released in 7.1)

This functionality will allow you not to specify tuple names in some cases. If applicable, tuple elements may get optional names.

Let’s consider the example:

Instead of writing (f1: x.f1, f2: x?.f2), we can simply write (x.f1, x?.f2).

In this case, the first element of the tuple will get the f1 name, another one – f2.

Now, the tuple would be unnamed to which elements we could refer by item1 and item2.

Optional names are especially useful when using tuples in LINQ.

// both c and result contain elements with the f1 and f2 names
var result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1);

Drawbacks

The main drawback of introducing this functionality is compatibility with C# 7.0. The example is as follows:

Action y = () => M();
var t = (x: x, y);
t.y(); // extension method y() is used to be selected. Now, lambda is called

Still, we can accept this small compatibility failure, as the release period between 7.0 and 7.1 is small.

Actually, when using 7.0, Visual Studio warns that

Tuple element name ‘y’ is inferred. Please use language version 7.1 or greater to access an element by its inferred name.

The full example of the code is as follows:

class Program
{
   static void Main(string[] args)
   {
       string x = "demo";
       Action y = () => M();
       var t = (x: x, y);
       t.y(); // extension method y() was used to be selected, while now the lambda is called  
   }

   private static void M()
   {
       Console.WriteLine("M");
   }
}

public static class MyExtensions
{
   public static void y(this (string s, Action a) tu)
   {
       Console.WriteLine("extension method");
   }
}

Note: If you use .NET 4.6.2 and lower versions, it is necessary to install the System.ValueTuple NuGet package to try this example.

Also Read:

Functional F# that slowly appears in C#

Tags: Last modified: September 23, 2021
Close