Нововведения в C# 12

Последнее обновление: 01.12.2023

Выражения коллекций

В C# 12 упрощен способ создания массивов и коллекций с помощью выражения коллекций (collection expression), которые представляют унифицированный подход к созданию коллекций. Так, если раньше создание массивов выглядело так:

int[] nums1 = { 1, 2, 3, 4 };
int[] nums2 = new int[] { };   // пустой массив

Теперь можно писать так:

int[] nums1 = [ 1, 2, 3, 4 ];
int[] nums2 = [];   // пустой массив

Аналогичным образом можно использовать выражения коллекций для создания других типов коллекций:

List<int> list1 = [1, 2, 3, 4];
List<int> list2 = []; //  пустой список
Span<int> span1 = [1, 2, 3, 4];

Первичные конструкторы

Первичные конструкторы (Primary constructors) позволяют добавлять параметры к определению класса/структуры и использовать эти параметры внутри класса/структуры:

var tom = new Person("Tom", 38);
Console.WriteLine(tom);

public class Person(string name, int age)
{
    public Person(string name) : this(name, 18) { }
    public string Name => name;
    public int Age => age;

    public override string ToString() => $"name: {name}, age: {age}";
}

Здесь для класса Person определен первичный конструктор с двумя параметрами - name и age. Эти параметры применяются для инициализации свойств Name и Age и используются в методе ToString().

За кадром для каждого параметра первичного конструктора в классе создается приватное поле, которое хранит значение параметра. Благодаря этому они могут использоваться в теле класса.

Кроме первичных конструкторов класс может определять дополнительные конструкторы, как примере выше. Но эти дополнительные конструкторы должны вызывать первичный конструктор:

public Person(string name) : this(name, 18) { }

Псевдонимы типов

C# 12 позволяет определять псевдонимы для любых типов. Например:

using People = System.Collections.Generic.List<Person>;

People people = new(){ new ("Tom", 38), new ("Bob", 42) };
people.ForEach(Console.WriteLine);

public record Person(string Name, int Age);

Здесь "People" выступает в качестве псевдонима для типа List<Person>

Другой пример:

using user = (string, int);
user tom = ("Tom", 38);
Console.WriteLine(tom);     // (Tom, 38)

Здесь имя user выступает в качестве псевдонима для кортежа типа (string, int)

Причем мы можем дать элементам кортежа имя:

using user = (string name, int age);
user tom = ("Tom", 38);
Console.WriteLine(tom.name);     // Tom
Console.WriteLine(tom.age);     // 38

Еще один пример:

using BinaryOp = System.Func<int, int, int>;

BinaryOp sum = (a, b) => a + b;
BinaryOp subtract = (a, b) => a - b;

DoOperation(10, 6, sum);        // 16
DoOperation(10, 6, subtract);   // 4

void DoOperation(int a, int b, BinaryOp op)
{
    Console.WriteLine(op(a, b));
}

Здесь для делегата типа System.Func<int, int, int> присваивается псевдоним BinaryOp.

Значения по умолчанию для параметров лямбда-выражений

Начиная с C# 12 параметры лямбда-выражений могут иметь значения по умолчанию:

var welcome = (string message = "hello")=> Console.WriteLine(message);

welcome("hello world"); // hello world
welcome();              // hello

ref-параметры только для чтения

Чтобы гарантировать, что ref-параметр не изменит своего значения, начиная с версии C# 12 можно применять ref-параметры только для чтения. Такие параметры предваряются ключевым словом readonly:

void Increment(ref readonly int n)
{
    // n++; // нельзя, иначе будет очишка компиляции
    Console.WriteLine($"Число в методе Increment: {n}");
}
 
int number = 5;
Increment(ref number);
Console.WriteLine($"Число после метода Increment: {number}");

В данном случае в метод Increment параметр n передается по ссылке и при этом он доступен только для чтения. При попытке изменить его значение мы получим ошибку на этапе компиляции.

Упрощение определения типов

Начиная с версии C# 12, если тип - класс/структура/интерфейс имеют пустое определение (не содержат полей, свойств, методов), то фигурные скобки после названия типа можно не использовать:

class Person;
struct User;
interface Human;
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850