What’s new in C# 12

C# 12 is the latest version of C# which is available in .NET 8. To try out C# 12 features you need visual studio IDE and dotnet 8 SDK.

In this blog, we’ll explore about the latest updates in C#.

  • Primary constructors
  • Collections Expressions
  • Ref and readonly
  • Default lambda parameters
  • Alias any type
  • Experimental attribute

Primary constructors

Let’s consider the below class,

Class Student {
public string FirstName {get; set;}
public string LastName {get; set;}
}

Consider a usecase, like whenever an object is being created for student class, it should have the value for FirstName and LastName. Before C# 12, we will create a parameterized constructor to solve it.

Class Student {
public string FirstName {get; set;}
public string LastName {get; set;}

public Student (string firstName, string lastName) {
FirstName = firstName;
LastName = lastName;
}

public void Print() {
Console.WriteLine(FirstName + " " + LastName);
}
}

Whenever you create an object, it expects you to send the first name and last name as the parameter. In C# 12 you can write it as,

Class Student (string firstName, string lastName) {
public void Print() {
Console.WriteLine(firstName + " " + lastName);
}
}

The idea behind primary constructors is to provide a concise syntax for initializing properties of an object directly in the constructor declaration. This can lead to cleaner and more readable code, especially when dealing with classes with a large number of properties.

Collections Expressions

Before C# 12, if you want to initialize a collection such as lists, arrays, dictionaries etc, you should do it with the help of new keyword.

int[] numbers = new int[] { 1, 2, 3};
List<string> names = new List<string> { "blogs", "meetups" };

In C# 12, you can initialize the collection without the new keyword.

int[] numbers = [1, 2, 3];
List<string> names = [ "blogs", "meetups" ];
Dictionary<string, int> testValue = [];

Ref and readonly

Consider the below code,

var age = 30;
Console.WriteLine($"Before calling the printer function : {age}");
var printer = new Printer();
printer.Print(ref age);
Console.WriteLine($"After calling the printer function: {age}");

Class Printer {
public void Print(ref int age) {
Console.WriteLine($"The age is {age}");
++age; // we are updating the value which updates its reference too
}
}

When the above code runs, the output will be

Before calling the printer function: 30
After calling the printer function: 31

It updates the value, which is outside the class because we are passing it as a reference, and we are modifying the value inside the class. From C# 12, you can mark the ref as readonly which doesn’t allow you to update the value.

Class Printer {
public void Print(ref readonly int age) {
Console.WriteLine($"The age is {age}");
++age; // This line will throw error as it is readonly
}
}

The above code does not allow you to update the value because it is marked as readonly.

Default lambda parameters

Consider the below lambda function

var printAge = (int age) => Console.WriteLine($"The age is {age}"); 
printAge(30); // This will print "The age is 30"
printAge(); // This will throw error because it expects a parameter

Before C# 12, you won’t be able to assign any default parameters to your lamda functions. But from C# 12, you can assign a default parameter.

var printAge = (int age = 20) => Console.WriteLine($"The age is {age}");
printAge(30); // This will print "The age is 30"
printAge(); // This will print "The age is 20"

In the above code the default parameter is 20.

Alias any type

From C# 12, you can alias tuples, pointers, array types, generic types, etc. So instead of using the full structural form of a tuple, you can now alias it with a short descriptive name which you can use everywhere. For example,

using Points = (int x, int y);

Then you can use it like any other type

var coordinates = new Points(2, 3);
Console.WriteLine(coordinates.x + " " + coordinates.y);

Experimental attributes

From C# 12, you can report warnings for references to types and members marked with System.Diagnostics.CodeAnalysis.ExperimentalAttribute

[ExperimentalAttribute("Risky")]
class AdvancedFeature {
public string featureId {get; set;}
}

So whenever you create an object for AdvancedFeature class it throws you error

var feature = new AdvancedFeature();
// The above line throws error
// Risky: 'AdvancedFeature' is for evaluation purposes only and is subject to change // or removal in future updates. Suppress this diagnostic to proceed

This feature will be very much useful for the library authors because it will be consumed by many external projects. If there are any breaking changes that will happen later, they can use this attribute to notify to the external consumers of the respective library.

Conclusion

I hope this blog gives you a detailed overview of the updates available in C# 12. If you come across any other interesting features, mention them in the comments section.

Happy Coding! 🙂

Leave a comment

Blog at WordPress.com.

Up ↑