Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Typescript

Happy New ... C# 9 Features!

3.91/5 (4 votes)
2 Jan 2020CPOL4 min read 8.6K  
New C# 9 features

Happy New ... C# 9 Features!

As one of my languages du jour, I've always had a fondness for C#. It was one of the first high-level languages that I learned in college and it's been part of my daily professional life for the better part of ten years. One of the things that's always been enjoyable about the language is the concept of constant innovation.

Features are constantly being adapted from other languages (looking at you F#, Kotlin, Typescript, and more) to help add features that would be greatly desired, extend existing functionality, or just apply an ample sprinkling of syntax sugar. I thought with the new year just beginning, let's take a look at some of the proposed features that are slated to find their way into the flagship Microsoft language in the near future!

It's worth noting that this is by no means a complete list and everything in this list, as with all things in active development, is subject to change / never happen.

So, let's get into it!

Using All the Things

One of the proposals that has been championed in the next release of C# has been the concept of extending using statements to improve resource management. At present, a using statement can require a bit of ceremony, however this proposal would add support for using statements to be used in a declarative fashion:

C#
if (condition)  
{
     using var file1 = new FileStream("...");
     using var file2 = new FileStream("...");

     // Omitted for brevity

     // Dispose file2
     // Dispose file1
}

This approach would handle freeing up the resources for any variables decorated with the using statement when the scope was closed. Another facet of the proposal is the concept of using pattern matching to identify the existence of a Dispose() method on a given class, which will be called similar to the example above when the scope has ended:

C#
switch(...)  
   case someCase:
       using var connection = new SqlConnection();

       // Omitted for brevity

       // Dispose connection (since SqlConnection has a Dispose() method)
       break;

Support for this feature does not require the targeted class to implement the IDisposible interface, but instead just contain a Dispose() method.

Check Yourself Before You Wreck Assign

A common pattern that you'll commonly see within applications is the use of a simple "is null" check prior to some assignment statement like the following:

C#
if (something == null)  
{
    something = someValue;
}

This proposal recommends introducing a new binary operator that aims to simplify this syntax similar to the improvements made with the null-coalescing operator:

C#
// The ??= operator is functionally equivalent to a null check followed 
// by an assignment statement (if null)
something ??= someValue;  

It's fairly low hanging fruit, but it provides some syntactic sugar for a common pattern that you're sure to see in many, many applications.

Null Checks Kotlinified No More

No one really likes writing countless null checks. Lines upon lines of if statements with nested exceptions being thrown, it's gross. In a vein similar to the previous feature, this proposal aims to eliminate the need for explicit null checking by allowing an operator ! to be added to a parameter to indicate to the compiler that a given value will not be null.

It would transform a snippet like the following:

C#
int CountWords(string sentence)  
{
    if (sentence is null) 
    {
        throw new ArgumentNullException(nameof(sentence));
    }

    // Omitted for brevity
}

Into a much terser, uncluttered form:

C#
// Notice the trailing '!' after the parameter name, which indicates
// it will not be null
int CountWords(string sentence!)  
{
    // Omitted for brevity
}

Let the Constructor Do the Work

Another proposal that has been or in some phase of discussion since C# 6 has been the idea of primary constructors, a feature that's been found in languages like Typescript, Kotlin, and other languages. The basic idea behind primary constructors is that they would simplify writing class constructors and boilerplate code in general by implicitly creating private fields from the arguments passed in by the constructor itself.

Let's look at an example of a class with a few private, readonly properties:

C#
public class Widget  
{
    private readonly int _foo;
    private readonly WidgetConfiguration _config;

    public Widget(int foo, WidgetConfiguration config)
    {
         _foo = foo;
         _config = config;
    }
}

The proposal would remove the need for the boilerplate field declarations as the constructor itself would handle creating the arguments passed in:

C#
public class Widget  
{
     public Widget(int _foo, WidgetConfiguration _config)
     {
          // If you wanted one of these properties to be publicly accessible, you could define
          // and set one of those here, otherwise the arguments will be privately accessible
          // as fields.
     }
}

If That Wasn't Simple Enough... How About Records?

If you enjoyed the last proposed feature, then you may find yourself doing a double-take with this one. Another proposal that has been toyed with for a while is the concept of records. Records are a simplified form for declaring classes and structs that supports some new features to simplify working with them (such as caller-receiver parameters and with expressions).

C#
public class Widget  
{
    // Properties (business as usual)
    public readonly string Foo;
    public readonly string Bar;

    // Definition of a With expression, which will allow you to 
    // easily create instances of a widget
    // from an existing instance
    public Widget With(string foo = this.Foo, string bar = this.Bar) => new Widget(foo, bar);
}

We can see this demonstrated below:

C#
var existingWidget = new Widget("foo", "bar");

// Now create a brand new instance with one of the properties changed
var clonedWidget = existingWidget.With(bar: "buzz");

// At this point clonedWidget looks like this: { Foo = "foo", Bar = "buzz" }

Records will also support the use of positional pattern matching along with the use of destruction in tandem to do some things like this:

C#
var widget = new Widget("foo", "bar");

// If the widget has a its Foo property set to "foo", then this condition will be met
if (widget is Widget("foo", var bar)) {  
    // Perform some operation here on the widget, 
    // the use of var above will function as destruction so you can
    // access it within this scope
    Console.WriteLine(bar); 
}

Records are one of the more involved features being proposed in C# 9, so if you are curious or want to learn more about them, I'd highly recommend checking out the full proposal on them here, which contains a wide range of examples, use cases, and more.

But Wait - There's More!

The features that were covered in this post are some of the more practical ones that might see everyday use, but these were by no means all of the current proposals. I'd encourage you, if you are interested in learning more about what else might be on the menu at the related milestone for C# 9 on GitHub.

There you'll find tons of additional features that weren't mentioned here such as:

Finally - the C# language is open-source and is always looking for contributors, opinions, and any folks that love the language to share their thoughts on what could make it better.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)