Tuesday, May 13, 2025

What's New in C# 12

C# 12 introduces several features that enhance syntax clarity, reduce boilerplate, and improve performance, particularly for object initialization and collections. One such feature is Primary Constructors, which brings concise constructor syntax to regular classes and structs—previously only available for records.

Here is an example of how to use Primary Constructors in C# 12:
 
public class Product(string name, decimal price) 
{ 
	public void PrintDetails() 
	{ 
	Console.WriteLine($"Product: {name}, Price: {price:C}"); 
	} 
} 
In this example, the Product class uses a primary constructor, where the parameters name and price are directly available throughout the class. This eliminates the need to manually declare private fields and assign values in a traditional constructor.

Another powerful addition in C# 12 is Collection Expressions, which simplify collection initialization and allow combining or spreading multiple collections.

Here is an example:
 
int[] baseNumbers = [1, 2, 3]; 
int[] moreNumbers = [..baseNumbers, 4, 5]; 
List<string> 
names = [ "Alice", "Bob", "Charlie" ]; 
In this snippet, the [..baseNumbers, 4, 5] syntax merges baseNumbers with additional elements into a new array. The use of square brackets and the spread operator (..) simplifies working with collections and makes the code more expressive.

C# 12 also introduces default parameter values for lambdas, making functional programming more flexible:

 
Func<string, string> greet = (string name = "Guest") => $"Hello, {name}!"; 
Console.WriteLine(greet()); // Output: Hello, Guest! 
Here, the lambda function greet provides a default value for name, allowing it to be called with or without arguments.

Another notable enhancement is the ability to create type aliases for any type—including arrays, tuples, and generic types:

 
using IntList = List<int>; 
using NameAgeTuple = (string Name, int Age); 
IntList scores = new() { 90, 80, 85 }; 
NameAgeTuple person = ( "David", 34 ); 
This improves readability and maintainability by allowing complex types to be referenced using simpler names.

Finally, the new [Experimental] attribute allows marking APIs as experimental to communicate instability to consumers:
 [Experimental("This feature is still under development")] 
void NewFeature() { } 
This is especially helpful in SDKs and library development where features may evolve over time.

No comments:

Post a Comment