DEV Community

loading...
Cover image for List of C# 9 features

List of C# 9 features

Andrei Fedotov
I write here some notes
・3 min read

Top-level statements

The very simple program on C# looks like the following

using System;
namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

but with C# 9 we can make it simpler:

System.Console.WriteLine("Hello World!");
Enter fullscreen mode Exit fullscreen mode

Target-Typed Object Creation

Let's imagine we have a class:

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }

    public Book()
    {

    }

    public Book(string title, string author)
    {
        Title = title;
        Author = author;
    }
}
Enter fullscreen mode Exit fullscreen mode

Usually we create objects like follow:

var book = new Book();
// or
Book book = new Book();
Enter fullscreen mode Exit fullscreen mode

With C# we can do:

Book book2 = new();
Book book3 = new("1", "A1");
Enter fullscreen mode Exit fullscreen mode

Init-only Setters

Consider we have a class Book

public class Book
{
        public string Title { get; set; }
        public string Author { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

and we can set values during the initialization. At the same time we can change the values as far as we have a setter for every field as well.

var book = new Book { Author = "1", Title = "2" };
book.Title = "2";
Enter fullscreen mode Exit fullscreen mode

Imagine a situation where we want only set values during the initialization and we want to restrict them after initialization. In C# 9 Init-only feature comes into play:

public class Book
{
        public string Title { get; init; }
        public string Author { get; init; }
}

var book = new Book { Author = "1", Title = "2" };
book.Title = "2"; // compile error
Enter fullscreen mode Exit fullscreen mode

Relational & Logical Patterns

Relational patterns permit the programmer to express that an input value must satisfy a relational constraint when compared to a constant value

public class Book{  public string Title { get; set; }   public string Author { get; set; }  public static decimal Postage(decimal price) => price switch    {       < 20 => 6.99m,      >= 20 and < 40 => 5.99m,        >= 40 and < 60 => 2.99m,        _ => 0  };}
Enter fullscreen mode Exit fullscreen mode

Records

We have a class:

public class Book{    public string Title { get; }    public string Author { get; } public Book(string title, string author)    {          Title = title;          Author = author;    }}
Enter fullscreen mode Exit fullscreen mode

And let's imagine we want to be able to create a book. We can do it as following:

var book = new Book("Title1", "Author1");
Enter fullscreen mode Exit fullscreen mode

and also we want to serialize the object and de-serialize

var json = JsonSerializer.Serialize(book);Console.WriteLine(json);var book2 = JsonSerializer.Deserialize<Book>(json);var isEqual = book == book2;Console.WriteLine($"book == book2: {isEqual}"); // false
Enter fullscreen mode Exit fullscreen mode

In console we'll see that de-serialized book is not the same book that was serialized. How can we make them the same? We can override equals operator:

public static bool operator ==(Book left, Book right) =>    left is object ? left.Equals(right) : right is null;
Enter fullscreen mode Exit fullscreen mode

if we override == operator we also have to override !- operator:

public static bool operator !=(Book left, Book right) => !(left == right);
Enter fullscreen mode Exit fullscreen mode

But we have not done anything to compare our object yet, so we have to override Equals method:

public override bool Equals(object obj) => obj is Book b && Equals(b);public bool Equals(Book other) => other is object &&  Title == other.Title && Author == other.Author;
Enter fullscreen mode Exit fullscreen mode

And we need to override GetHashCode and ToString methods.

public override int GetHashCode() => HashCode.Combine(Title, Author);public override string ToString() => $"{Title} - {Author}";
Enter fullscreen mode Exit fullscreen mode

Also, we have to make our class implement IEquatable<T> interface.

public class Book : IEquatable<Book>
Enter fullscreen mode Exit fullscreen mode

Finally we have to write a bunch of code for just one simple action. Full class:

public class Book : IEquatable<Book>{   public string Title { get; }   public string Author { get; }   public Book(string title, string author)   {       Title = title;       Author = author;   }   public static bool operator ==(Book left, Book right) =>       left is object ? left.Equals(right) : right is null;   public static bool operator !=(Book left, Book right) => !(left == right);   public override bool Equals(object obj) => obj is Book b && Equals(b);   public bool Equals(Book other) =>       other is object &&       Title == other.Title &&       Author == other.Author;   public override int GetHashCode() => HashCode.Combine(Title, Author);}
Enter fullscreen mode Exit fullscreen mode

Now Console.WriteLine($"book == book2: {isEqual}"); will output true.

There is a lot of boilerplate code.

Moreover, if we add a new field we will have to update every method.

With C# 9 we can use the record type for the same behavior. It allows making behavior for classes as if they were structures.

record Book(string Title, string Author)
Enter fullscreen mode Exit fullscreen mode

Extended partial methods

Now we can use modifiers and return values for partial methods.

public partial class Book{  public string Title { get; set; }   public string Author { get; set; }  public decimal Price { get; set; }  private partial decimal SetPrice();}public partial class Book{  private partial decimal SetPrice()  {       return 0m;  }}
Enter fullscreen mode Exit fullscreen mode

Covariant returns

In C# 9 we can return derived types in overridden methods.

public class Book{  public string Title { get; set; }   public string Author { get; set; }}public class CollectionBook : Book{  public string Edition { get; set; }}public abstract class BookService{  public abstract Book GetBook();}public class CollectionBookService : BookService{   public override CollectionBook GetBook()    {       return new CollectionBook();    }}
Enter fullscreen mode Exit fullscreen mode

Code: https://github.com/platinum-team/tech-talk-csharp9-features

Cheers!

Discussion (2)

Collapse
hanpari profile image
Pavel Morava

Microsoft has to introduce more and more features to make C# less verbose.

In an ideal world, Csharpists would switch to F# long ago and left C# behind as an obsolete artefact of premature design.

Collapse
saint4eva profile image
saint4eva

Lol