Primary constructors

One major feature in C# 12 is primary constructors. A primary constructor is declared on the type declaration instead of inside the class body. Its parameters can be used directly in members.

Record types

public record Address(string FirstName, string LastName);

Class types

public class Person(string firstName, string lastName)
{
    public override string ToString()
    {
        return $"{firstName},{lastName}";
    }
}
public Person(string firstName) : this(firstName, "hello")
{

}

Collection expressions

C# 12 adds collection expressions for concise collection initialization.

// Create an array:
int[] a = [1, 2, 3, 4, 5, 6, 7, 8];

// Create a list:
List<string> b = ["one", "two", "three"];

// Create a span
Span<char> c  = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'];

// Create a jagged 2D array:
int[][] twoD = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

// Create a jagged 2D array from variables:
int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[][] twoDFromVariables = [row0, row1, row2];

Range and index usage

sequence[0] is the first element. ^n means counting from the end. For any number n, index ^n is equivalent to sequence.Length - n.

string[] strs = ["a", "b", "c", "d", "e","f"];

string[] strs1= strs[0..3];

string[] strs2 = strs[2..^2];

string[] strs3 = strs[^3..^1];

Default lambda parameters

var IncrementBy = (int source, int increment = 1) => source + increment;

Spread operator

int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[] single = [.. row0, .. row1, .. row2];

Type aliases

using MyPerson = ConsoleApp1.Person;
using MyType = (string FirstName,int LastName);