Exploring C# 11 Features: What's New and How to Use It
C# has been a popular programming language for many years now. It continuously evolves to include new features and adopt recent trends. Its flexibility makes it a language ideal for many different domains and platforms like desktop applications, enterprise systems, web development, games, cross-platform, and native mobile applications. Back when Microsoft launched .NET 7, this also included a new version of C# with version number 11. The new version improves developer productivity and code quality even further. In this blog post, I will explore some of the important features introduced in C# 11.
Raw string literals
This one resolves a big problem for C# developers. We often need to add special characters in strings such as \
, ’
, and "
. Also, newlines need escaping to work properly. But with the arrival of C# 11, we can simply write any character in the string by enclosing the string with 3 double quotes. Here is how to use it:
string longStr = """
For a long time, it was widely believed that lorem ipsum originated as meaningless filler text.
"It's not actual Latin, although it appears to be, and it doesn't convey any real meaning,"
explained Before & After magazine in response to an inquisitive reader.
"The 'words' are crafted to roughly match the letter frequency of English,
which is why it appears somewhat genuine at first glance."
Some strings also include "quoted text" within them.
""";
List Pattern
List Pattern Eases pattern matching by allowing developers to match sequences of elements within an array or a list. Previously to check a pattern in the list:
var values = new List<int> { 10, 20, 30, 40, 50 };
We used code like this:
bool startsWithTenTwentyThirty =
values.Count >= 3
&& values[0] == 10
&& values[1] == 20
&& values[2] == 30;
With List Pattern we can simplify the code to this:
bool startsWithTenTwentyThirty = values is [10, 20, 30, ..];
UTF-8 string literals
With the update, C# allows us to create string values as UTF-8 encoded. Traditionally, C# hardcords string in UTF-16. Among other benefits, this feature reduces the overhead of converting strings when doing web development, as the HTTP string protocol uses UTF-8. Here's how to specify the encoding using the new syntax:
var u8String = "Hi, I am a UTF-8 string!"u8;
Required Members
Another feature added in C# is in Object creation. When creating an object of a class, we were unable to enforce constraints on properties. Now we can mark properties to be initialized at the time of instantiation:
public class User
{
public required string FirstName { get; init; }
public required string Email { get; init; }
public string LastName { get; set; }
}
var user = new User
{
FirstName = "John",
LastName = "Doe",
};
The code will cause the following error since the Email
property, marked as required, is not set when creating the User
object:
Generic math support
Another simple but important introduction in C# 11 is generic math support. C# now allows users to perform mathematical operations on generic types while keeping the type-safety. We can implement static members and overloadable operators of numerical generic interfaces which was not the case before. We needed to implement a method or overload operator for each type separately or by using dynamic type.
Previously we had to do this:
public static int Add(int a, int b) => a + b;
public static double Add(double a, double b) => a + b;
Or this:
public static T Add<T>(T a, T b)
{
dynamic da = a;
dynamic db = b;
return da + db;
}
Both of them had several issues. If the operation is not supported, an error will be thrown only at runtime. In addition, dynamic adds a performance overhead due to its runtime type resolution.
With the arrival of C# 11, we can define a generic implementation for such operations:
using System;
using System.Numerics;
public static class MathOperations
{
// A generic method that adds two numbers
public static T Add<T>(T a, T b) where T : INumber<T>
{
return a + b;
}
// A generic method that multiplies two numbers
public static T Multiply<T>(T a, T b) where T : INumber<T>
{
return a * b;
}
}
// Inside Main method
// Adding integers
int intResult = MathOperations.Add(10, 20);
Console.WriteLine($"Integer Addition: {intResult}");
// Adding doubles
double doubleResult = MathOperations.Add(10.5, 20.3);
Console.WriteLine($"Double Addition: {doubleResult}");
// Multiplying complex numbers
Complex c1 = new Complex(1, 2);
Complex c2 = new Complex(3, 4);
Complex complexResult = MathOperations.Multiply(c1, c2);
Console.WriteLine($"Complex Multiplication: {complexResult}");
It brings the following perks to the code
- Code Reusability: writing a single method works with multiple numeric types.
- Ease of coding: Developers do not need to think and write the same logic for each numeric type separately.
- Type Safety: The compiler validates the types supporting and the defined operations in the method. This makes Users get to know type error at the compile time.
- Flexibility: Any additional numeric types use the same generic methods without modifying the existing code.
Newlines in string interpolations
An update that improves the readability of the code is Newlines in string interpolations. The string between curly braces { and } allows newline to include some interesting ways of formatting it. Spaces and newlines does not affect the string but they are just for layout and readability. Earlier, it was not allowed and users have to format it by appending or else.
double bmi= 24;
string message = $"Body at BMI {bmi} is {bmi switch
{
>= 30=> "Obese",
>= 25 => "Overweight",
>= 18.5 => "Normal",
< 18.5 => "Underweight"
}}";
File local types
Apart from updates, this one is a whole new feature added to C#. File-local types enable users to define types (like classes, structs, or records) within the scope of the file in which they are defined. The feature adds new encapsulation which avoids naming collision within a project. Multiple types with the same can reside in their file-local scope.
Here's a quick example:
// File: UserRepo.cs
file class UserHelper
{
public void GetMessage()
{
Console.WriteLine(" I am user helper ");
}
}
public class Program
{
public static void Main()
{
var userHelper = new UserHelper();
userHelper .GetMessage();
}
}
The file
keyword specifies the class scope. Hence the UserHelper
class can only be accessible in the UserRepo
file.
Conclusion
C# is a prominent programming language maintained by Microsoft. Its popularity is well earned from its robustness and versatility. It is one of the few languages that is used by various domains including web development, game development, desktop applications, native, and cross-platform mobile apps. Microsoft keeps improving it with version-wise features. C# 11 is a newer version that brought so many important features easing the developer community by enhancing performance and readability. We discussed some important updates of C# 11 along with examples.
elmah.io: Error logging and Uptime Monitoring for your web apps
This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website