New Features In C# 11 | Learn C#


In this article, we gonna discuss the new features in C# 11 with examples. C# programming language was launched in 2000 and now it is at its version 11. As part of this article, we are going to discuss the following pointers.

Raw string literals

A new format for string literals is called a raw string literal. Without the need for escape sequences, raw string literals can include any content, including new lines, embedded quotations, whitespace, and other special characters.

There is at least three double-quote ("") characters at the beginning of a raw string literal. The same amount of double-quote characters is used to close it. A raw string literal typically begins with three double quotes on a single line and ends with three double quotes on a different line. The newlines that come after the first quotation and before the last quote are not part of the text's final form.

Let's say I have a system that dynamically builds some XML in this case so we would have something like a string Builder as below.

using System.Text;
var sb = new StringBuilder();
//var xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
var xml = """<?xml version="1.0" encoding="UTF-8"?>""";

New Features In C# 11

List Patterns

List patterns are an extension of pattern matching that allows them to match lists of elements or arrays of elements. Sequence is [1, 2, 3], for instance, is true when the sequence consists of an array or a list of three integers (1, 2, and 3). Any pattern, such as a constant, type, property, or relational pattern, can be used to match elements. Any single element matches the discard pattern (_), and any sequence of zero or more elements matches the new range pattern (..).

I'm gonna have an array now, even though the name is called list patterns, this also applies to arrays. Basically, it applies to anything that is countable or it has a "count" property.

int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]);
Console.WriteLine(numbers is [1, 2, 4]);
Console.WriteLine(numbers is [1, 2, 3, 4]);
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]);
if (numbers is [var first, .. var rest])

New Features In C# 11

Generics on Attributes

Generic attribute support has been included in C# 11. Hence, in essence, passing System. We may define a generic class, just like any other generic class, by passing a type as a parameter to constructor. This class will take any number of types as parameters.

So, for example, if I go to this user class as shown below, let's say I have a validator attribute and I want to specify what type the validator should be that will validate this user. Now, previously, we would have to pass down the type as the type itself and use a type, which really limited what you could do. Eventually, we would pass it down into a type object and then try to do all your reflection, and that's because before C++ 11, we couldn't go ahead and have a generic T-Type parameter here, so we had to pass it down as a parameter in the constructor, but this is no longer the case. We no longer need this, we can just say "type of T" and pass that like below.

Previously, we use to have a constraint because ultimately we only want things that implement the Ivalidator to be possible there, and that's a check we would have to do in runtime in our validator logic but no longer that's the case. We can now just say "where T: Ivalidator" and now we're going to limit what we can pass down.

// Generic Attributes with C# 11
// Validator attribute - A generic class now
// Constraints are specified on type parameters.
using System.ComponentModel.DataAnnotations;
public class ValidatorAttribute < TValidator > : Attribute where TValidator: IValidator {
    public Type ValidatorType {
    public ValidatorAttribute() {
        ValidatorType = typeof(TValidator);

Extended nameof scope

When writing a method declaration, we can now use the "nameof" operator in attribute declarations to refer to the names of the method's parameters. This allows us to add attributes to the method or its parameters using the names of those parameters. This feature is particularly useful for adding attributes for nullable analysis.

public class Sample {
    public void Test(string text) {
        void LocalFunction < T > (T param) {}
        var lambdaExpression = ([Name(nameof(aNumber))] int aNumber) => aNumber.ToString();


In this article, we discussed few new features in C#11. In the next article, we will look into some more features. 

Similar Articles