Today in C# you have the possibility to use object initializers. Using object initializers you have the possibility to set properties of an object immediately after the object is created and do this in one statement. It looks like:
With ‘init-only’ properties we have made the properties on that object immutable. If you want to do that with the whole object C# 9.0 brings you a solution in the form of ‘record classes’. You can create a record class by adding the ‘data’ keyword before the class definition. When you do that an instance of that class will be immutable and more behave like a value type then as an object. I won’t go into detail explaining how this all works because it is perfectly described in this blogpost:
But in the end you can write a record class as follows:
My opinion: My first question when I read about record classes was: “Why not just use structs?”. And the answer to that took me a while to understand. Then I found (an already old article) on c-sharpcorner.com: https://www.c-sharpcorner.com/article/candidate-features-for-c-sharp-9/.
The answer to my question they give there is as follows:
“Structs are a thing you have to have some discipline to implement. You don’t have to make them immutable. You don’t have to implement their value equality logic. You don’t have to make them comparable. If you don’t, you lose almost all of their benefits, but the compiler doesn’t enforce any of these constraints.”
And I think they are right here. With record classes you have something natively supported in the language that under the hood generates all the code so that it really behaves like a value type and equality is correctly implemented. So my conclusion is that record classes are a good addition to C#.
When you write a program in C# you always need a class with a static Main method. This is the starting point of every application. A simple “Hello World” program looks like this: using System;
The argument here is that you don’t need to write the same boilerplate code every time and that it should be more easy for newcomers to the language. Of course you can only have one file in your application that does this (just like you could have only one static Main method).
My opinion: This is one of the features where I don’t fully understand why they added this. I understand that it saves some code but this isn’t code that you have a lot of in your application. It is not repeated in every class so you don’t save a lot of code. The other argument is that it will be more easier for newcomers but I personally doubt if that is the case. For me, and also for a newcomer, I think it is very clear that every program has one entry point and that is where the static Main method is. Using top-level programs that stays the same but then you can only have one file where you start your application code right after the using statements. A bit less clear in my opinion.
Improved pattern matching
Since C# 7.0 there have been a lot of improvements and additions to pattern matching in C#. In C# 9.0 this is also the case. As a programmer you get more and more possibilities to use patterns in switch statements. The followings are added:
- Simply type patterns –> Just switch on type without declaring an unused variable
- Relational patterns –> Use a nested switch expression
- Logical patterns –> Use keywords like and, or and not in your patterns
All the above patterns are described here:
My opinion: I think it is always good to have more possibilities to specify the cases in your switch statements. In this way code can become more clear and easy to read.
Improved target typing
With “target typing” an expression gets it type from the context it is in. This is already the case in many situations but there are situations where this wasn’t the case. An example of this is when you use coalescing operator. In the current version of C# the following examples are not supported while it is in C# 9.0.
In the current version you always had to cast the objects to the same type to make it work.
Another example, that is less useful in my opinion, is that you can leave out the type after the new keyword when the declaring type is specified. For example:
When you have a base class with a virtual or abstract method that can/must be overwritten, until now you always had to have the same return type in the deriving class. That makes sense because changing the return type would make it a different kind of method. The method signature stays the same but with a different return type you can get into trouble in the code where the method is called. But let’s take a look at the following example.
In this example the Car class overrides the ‘GetFuel’ method. The implementation of the ‘GetFuel’ method in the Car class always returns a new instance of ‘Gasoline’ (which is a subclass of Fuel). Calling code on a car then always needs to cast the return type to the type ‘Gasoline’ if they want to use it as that type. In C# 9.0 it is possible to override the method and change the returning type to the derived class. The code would look as follows:
My opinion: I think this is a good addition because it makes your code more clear and more easy to understand.
C# 9.0 gives us more possibilities to make it easier to create and read code. I think useful features are added and maybe there are some that don’t add a lot (like top-level programs). But the features that don’t add a lot are not features you have to use. Looking forward I think C# is only getting better and easier and that is a positive development!