C# 11 is about to Release in November 2022 with some great features. The most of the features are focused on pure performance (up to 73.5% faster). There’are many improvements that will change the way you code. In this Article, I’m going to list all C# 11 Features with Code Examples & I’ll also compare C# 10 vs C# 11 Code for better understanding.

Here’s the List of All C# 11 Features.

Required Members

C# 11 introduces a new

required modifier to fields & properties to impose constructors & callers to initialize those values.

A new SetsRequiredMembers attribute on the constructor tells the compiler that it initializes all required members.

// Initializations with required properties 
var p1 = new Person { Name = "Shehryar", Surname = "Khan" }; 
Person p2 = new("Shehryar", "Khan");

// Initializations with missing required properties 
var p3 = new Person { Name = "Shehryar" }; 
Person p4 = new();

public class Person {
  public Person() {}

  [SetsRequiredMembers] 
  public Person(string name, string surname)
  {
    Name = name; 
    Surname = surname;
  }

  public Guid Id { get; set; } = Guid. NewGuid(); 
  public required string Name { get; set; } 
  public required string Surname { get; set; }
}

Raw string Literals

C# 11 preview introduces raw string literals.

It allows containing of arbitrary text without escaping.

The format is minimum 3 double quotes """.."""

Combining with string interpolation, the count of $ denotes how many braces in a row start & end the interpolation.

C# 10
string name = "Shehryar";
string surname = "Khan";

string jsonString = 
  [email protected]"
  {{
    'Name': {name},
    'Surname': {surname}
  }}
  ";
C# 11
string name = "Shehryar";
string surname = "Khan";

string jsonString = 
  $$"""
  {
    "Name": {{name}},
    "Surname": {{surname}}
  }
  """;

UTF-8 string literals

C# 11 preview introduces UTF-8 string literals.

It allows converting only UTF-8 characters to their byte representation at compile time.

C# 10
byte[] array = Encoding.UTF8.GetBytes("Hello World");
C# 11
byte[] array = "Hello World";

List Patterns

C# 11 preview introduces list patterns.

It expand pattern matching to match sequences of elements in a list or an array.

You can use list patterns with any pattern, including property, type, constant, & relational patterns.

var numbers = new [] { 1, 2, 3, 4 };
// List and constant patterns 
Console.WriteLine(numbers is [1, 2, 3, 4]); // True 
Console.WriteLine(numbers is [1, 2, 4]); // False
// List and discard patterns 
Console.WriteLine(numbers is [_, 2, _, 4]); // True 
Console.WriteLine(numbers is [.., 3, _]); // True
// List and logical patterns 
Console.WriteLine(numbers is [_, >=2, _, _]); // True 

Newlines in string interpolation expressions

C# 11 preview introduces newlines in string interpolation.

It allows any valid C# code between { }, including newlines, to improve code readability.

It also helpfuls when you want to use longer C# expressions in interpolation, e.g. LINQ queries, pattern matching or switch expressions.

// switch expression in string interpolation 
int month = 5; 
string season = $"The season is {
  month switch {
    1 or 2 or 12 => "winter",
    > 2 and < 6 => "spring", 
    > 5 and < 9 => "summer", 
    > 8 and < 12 => "autumn",
    - => "Unknown. Wrong month number",
  }
}.";

Console.WriteLine(season); 
// The season is spring.

// LINQ query in string interpolation 
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6 }; 
string message = $"The reversed even values of {nameof(numbers)} are { 
  string.Join(", ", numbers.Where(n => n % 2 == 0)
      .Reverse())
}.";

Console.WriteLine(message); 
// The reversed even values of numbers are 6, 4, 2. 

Auto-default structs

The C# 11 compiler itself initializes any property or field not initialized by a constructor in the structs.

Such code doesn’t compile in the previous C# versions.

The compiler sets the default values.

C# 10
struct Person {
  // Auto-implemented property 'Person.Age 
  // must be fully assigned before control 
  // is returned to the caller. 
  public Person(string name)
  {
    Name = name;
  }

  public string Name { get; set; } 
  public int Age { get; set; }
}
C# 11
struct Person {
  public Person(string name)
  {
    Name = name;
  }

  public string Name { get; set; } 
  public int Age { get; set; }
}

Pattern match Span<char> on a constant string

Using pattern matching, we can test if the string has a certain constant value in C#.

C# 11 allows pattern matching a Span<char> & ReadOnlySpan<char> on a constant string.

C# 10
ReadOnlySpan<char> strSpan = "SK".AsSpan();
if (strSpan == "SK")
{
  Console.WriteLine("Hey, SK");
}
C# 11
ReadOnlySpan<char> strSpan = "SK".AsSpan();
if (strSpan is "SK")
{
  Console.WriteLine("Hey, SK");
}

Generic attributes

C# 11 introduces the generic attributes.

C# 10
class MyType 
{ }

class MyAttribute : Attribute
{
  private Type type;
  
  public MyAttribute(Type type)
  {
    _type = type;
  }
}

[MyAttribute(typeof(MyType))] 
class Myclass {}
C# 11
class MyType
{ }

class GenericAttribute<T> : Attribute
  where T : MyType
{
  private T _type;
}

[GenericAttribute<MyType>] 
class MyClass
{ }

Extended nameof scope

C# 11 expand scope of nameof expressions.

We can specify the name of a method parameter in an attribute on the parameter declaration or method.

This can be used in adding attributes for code analysis.

public class MyAttr : Attribute
{
  private readonly string _paramName; 
  
  public MyAttr(string paramName)
  { 
    _paramName = paramName;
  }
}

public class MyClass
{
  [MyAttr(nameof(param))]
  public void Method(int param, [MyAttr(nameof(param))] int anotherParam)
  { }
}

An unsigned right-shift operator

C# 11 introduces an unsigned right-shift operator >>>.

It shifts bits right without replicating the high order bit on each shift.

int n = -32; 
Console.WriteLine($"Before shift: bin = {Convert.ToString(n, 2), 32}, dec = {n}");

int a = n >> 2; 
Console.WriteLine($"After >>: bin = {Convert.ToString(a, 2),32}, dec = {a}");

int b = n >>> 2; 
Console.WriteLine($"After >>>: bin = {Convert.ToString(b, 2),32}, dec = {b}");

// Output: 
// Before shift: bin = 11111111111111111111111111100000, dec = -32 
// After >>: bin = 11111111111111111111111111111000, dec = -8 
// After >>>: bin = 111111111111111111111111111000, dec = 1073741816

Static abstract members in interfaces for generic math support

C# 11 introduces static abstract members in interfaces.

We can add static abstract members in interfaces to define interfaces that include other static members, overloadable operators, and static properties.

public interface IAdditionOperators<TSelf, TOther, TResult>
    where TSelf : IAdditionOperators<TSelf, TOther, TResult>
{
  static abstract TResult operator +(TSelf left, TOther right);
}

Numeric IntPtr

A little improvement in C# 11.

The nint and nuint types now alias System.IntPtr and System.UIntPtr respectively.

string str = "Hello!";
IntPtr intPtr = Marshal.StringToHGlobalAnsi(str); 
nint nInt = Marshal.StringToHGlobalAnsi(str);

unsafe
{
  byte* src = (byte*)intPtr.ToPointer(); 
  byte* dst = (byte*)nInt.ToPointer();
}

That’s all for now. Thank you for reading. I have also list all .NET 7 Features. You must have a Look.

What’s coming with .NET 7?


Tags