File-scoped namespace declaration
In C# 9 Top Level Statement feature was introduced. It allows in the app's entry point file not to write a boilerplate code.
Instead of the following:
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
It's enough only one line of code vs ten.
Console.WriteLine("Hello World!");
And it was amazing but having such ability only in one place does not bring much profit especially in a big project. So, C# 10 goes further and it brings a feature with the name File-scoped namespace declaration.
Let's consider an example. We have a project. It contains two classes. We see that the class is declared inside the namespace. It is inside the curly braces
namespace _1._File_Scoped_Namespace
{
public class Author
{
public string Name { get; set; }
public string LastName { get; set; }
public Author(string name, string lastname) =>
(Name, LastName) = (name, lastname);
}
}
File-scoped namespace declaration allows to get rid of the curly braces and make the code even more elegant. After the namespace, we need to put the semicolon.
namespace _1._File_Scoped_Namespace;
public class Author
{
public string Name { get; set; }
public string LastName { get; set; }
public Author(string name, string lastname) =>
(Name, LastName) = (name, lastname);
}
Extended property patterns
A new feature which is called Extended property patterns is highly useful for the conditions with nested properties.
Let's see in action. We have a Book
class. And we want to implement a method that will tell us if the book has a discount.
public static bool doesHaveDiscount(Book book)
{
return false;
}
Let's agree if the author's last name matches the specific value then we have a discount, otherwise, we don't.
public static bool doesHaveDiscount(Book book) =>
book switch
{
{ Author: { LastName: "Richter" } }
or { Author: { LastName: "Price" } } => true,
_ => false
};
We see nested properties of the author's object. Now we can simplify this construction by accessing the property with the dot.
public static bool doesHaveDiscount(Book book) =>
book switch
{
{ Author.LastName: "Richter" }
or { Author.LastName: "Price" } => true,
_ => false
};
It makes the code more readable and cleaner.
Constant interpolated strings
Strings iInterpolation is very cool because we can put the object right inside the string without leaving its borders.
public string ThankYouMessage()
{
return string.Empty;
}
Let declare two variables. And make an interpolation for the second one.
var message = "Thank you for buying the book!";
var thankYouMessage = $"{message} Enjoy";
In C# 10 we can declare those strings as the constants because it is obvious that the values are not intended to change.
public string ThankYouMessage()
{
const string message = "Thank you for buying the book!";
const string thankYouMessage = $"{message} Enjoy";
return thankYouMessage;
}
Records
One of the features of C# 9 was the record types. Long story short they allow to make classes immutable. C# 10 goes further and now we can create record structures. Let's consider the immutable structure
public readonly record struct Point
{
public int X { get; }
public int Y { get; }
}
After the name of the structure, we can pass the parameters.
public readonly record struct Point(int X, int Y);
and get rid of the rest of the code.
Also, in C# 10 we have the ability to add the sealed
keyword while overriding the ToString()
method in a record type. It tells the compiler: "don't create ToString()
for all inherited types, use this one".
record Circle
{
public sealed override string ToString()
{
return typeof(Circle).Name;
}
}
Assignment and declaration in the same deconstruction
The next feature is related to deconstruction. In previous versions, we could assign the values while deconstruction, or we could initialize them first and then assign them.
internal class Author
{
public string Name { get; set; }
public string LastName { get; set; }
public Author(string name, string lastname) =>
(Name, LastName) = (name, lastname);
public void Deconstruct(out string name, out string lastname) =>
(name, lastname) = (Name, LastName);
public override string ToString() =>
$"{Name} {LastName}";
}
var author = new Author("Andrei", "Fedotov");
Console.WriteLine(author);
(string name1, string lastName) = author;
Console.WriteLine(name1);
Console.WriteLine(lastName);
var name2 = string.Empty;
var lastname2 = string.Empty;
(name2, lastname2) = author;
Console.WriteLine(name2);
Console.WriteLine(lastname2);
C# 10.0 removes that restriction.
var lastname3 = string.Empty;
(var name3, lastname3) = author;
Console.WriteLine(name3);
Console.WriteLine(lastname3);
Global using directives
One more feature is Global using directives.
If importing the same namespaces in each app's file is annoying you then this feature is for you. C# 1- allows mark the imports as global and they will be imported into the files automatically,
global using System.Collections.Generic;
global using System.Linq;
namespace _6._Global_Using_directive;
public class Store
{
private readonly IEnumerable<Book> Books;
public Store(IEnumerable<Book> books) => Books = books;
public IEnumerable<Book> GetBooks(Author author) =>
Books.Where(b => b.Author.LastName == author.LastName);
}
Moreover, in the project configuration, there is a flag to enable implicit usings.
<ImplicitUsings>enable</ImplicitUsings>
Improvements of structure types
Since C# 10 we can declare the parameterless constructor for the structures.
public struct Point
{
public Point()
{
X = double.NaN;
Y = double.NaN;
}
public Point(double x, double y) =>
(X, Y) = (x, y);
public double X { get; set; }
public double Y { get; set; }
public override string ToString() =>
$"X: {X}, Y: {Y}";
}
var point = new Point(1,2);
Console.WriteLine(point); // X: 1, Y: 2
var point2 = new Point();
Console.WriteLine(point2); // X: NaN, Y: NaN
var point3 = default(Point);
Console.WriteLine(point3); // X: 0, Y: 0
default ignores the parameterless constructor and gives the default value for a type.
The repo with the examples is here.
Thank you for reading the post, I hope you enjoyed it.
You also might want to check C# 9 list of features.
Cheers!
Top comments (0)