Skip to content

Latest commit

 

History

History

7.3

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

C# 7.0 | C# 7.1 | C# 7.2 | C# 7.3

Содержание:

ПОВЫШЕНИЕ ПРОИЗВОДИТЕЛЬНОСТИ БЕЗОПАСНОГО КОДА:

Индексирование полей fixed без закрепления

Локальные переменные ref могут быть переназначены

Массивы stackalloc поддерживают инициализаторы

Больше типов поддерживают инструкцию fixed

Расширенные универсальные ограничения

УЛУЧШЕНИЕ СУЩЕСТВУЮЩИХ ФУНКЦИЙ:

Поддержка == и != для кортежей

Подключение атрибутов к резервным полям для автоматически реализуемых свойств

Критерии для разрешения перегрузки метода in

Расширение переменных выражений в инициализаторах

Улучшенный отбор потенциальных перегрузок

НОВЫЕ ПАРАМЕТРЫ КОМПИЛЯТОРА:

Параметр компилятора publicsign

Параметр компилятора pathmap


ПОВЫШЕНИЕ ПРОИЗВОДИТЕЛЬНОСТИ БЕЗОПАСНОГО КОДА

Расширяются возможности гарантированно безопасного кода – 
приоритетно использовать безопасные конструкции.

"Индексирование полей fixed без закрепления"

Представлена следующая структура с массивом фиксированного размера (Буферы фиксированного размера):

unsafe struct MyBuffer
{
    public fixed int fixedBuffer[10];
}

В более ранних версиях C# переменную необходимо закрепить, чтобы получить доступ к целым числам, входящим в fixedBuffer:

// оператор fixed устанавливает указатель на первый элемент
unsafe void AccessMyBuffer()
{
    fixed (int* intPtr = myBuffer.fixedBuffer)
    {
        int p = intPtr[5];
    }
}

Теперь такой код компилируется в безопасном контексте, не требуется объявлять второй фиксированный указатель int* intPtr на fixedBuffer. Контекст unsafe по-прежнему является обязательным.

Переменная p обращается к одному элементу в fixedBuffer. Для этого не нужно объявлять отдельную переменную int*.

class MyClass
{
    MyBuffer myBuffer = default;

    unsafe void AccessMyBuffer()
    {
        int p = myBuffer.fixedBuffer[5];
    }
}

"Локальные переменные ref могут быть переназначены"

До версии C# 7.3 ссылочные локальные переменные (Возвращаемые ссылочные значения) не переназначались после инициализации так, чтобы они ссылались на другое хранилище. Теперь локальные переменные ref можно переназначить другим экземплярам после инициализации:

// инициализация
ref VeryLargeStruct refLocal = ref veryLargeStruct;
// переназначение, refLocal ссылается на другое хранилище
refLocal = ref anotherVeryLargeStruct;

"Массивы stackalloc поддерживают инициализаторы"

Синтаксис инициализации массиивов с помощью инициализатора, теперь применим к массивам, в объявлении которых есть stackalloc (stackalloc):

var arr = new int[3] {1, 2, 3};
var arr2 = new int[] {1, 2, 3};

int* pArr = stackalloc int[3] {1, 2, 3};
int* pArr2 = stackalloc int[] {1, 2, 3};

"Больше типов поддерживают инструкцию fixed"

Оператор fixed работает с дополнительными типами, помимо массивов, строк, буферов фиксированного размера и неуправляемых переменных, можно применять для System.Span<T> и связанных типов.

Любой тип, реализующий метод GetPinnableReference, который возвращает ref T или ref readonly T, можно зафиксировать (GetPinnableReference должен преобразовывать переменную ref в неуправляемый тип).


"Расширенные универсальные ограничения"

Можно указать тип System.Enum или System.Delegate в качестве ограничения базового класса для параметра типа.

Доступно новое ограничение unmanaged, чтобы указать, что параметр типа должен быть неуправляемым типом.

Неуправляемый тип – это тип, который не является ссылочным и не

содержит ни одного ссылочного типа на любом уровне вложения.


УЛУЧШЕНИЕ СУЩЕСТВУЮЩИХ ФУНКЦИЙ

"Поддержка == и != для кортежей"

Типы кортежей в C# теперь поддерживают операторы == и != работающие путём сравнения каждого элемента левого аргумента с каждым элементом правого аргумента по порядку.

Оператор == перестаёт сравнивать элементы, как только будет обнаружена неравная пара. Оператор != перестаёт сравнивать элементы, как только будет обнаружена равная пара.

var left  = (a: 5, b: 10);
var right = (a: 5, b: 10);
Console.WriteLine(left == right); // true

Если один из кортежей допускает значение NULL, функция проверки кортежей на равенство выполняет неявное преобразование:

var left = (a: 5, b: 10);
var right = (a: 5, b: 10);
(int a, int b)? nullableTuple = right;
Console.WriteLine(left == nullableTuple); // true

Дополнительно выполняется неявное преобразование каждого элемента обоих кортежей (преобразования для использования форм, допускающих значение NULL, расширяющие преобразования и другие неявные преобразования):

var left = (a: 5, b: 10);
(int? a, int? b) nullableMembers = (5, 10);
Console.WriteLine(left == nullableMembers); // true

(long a, long b) longTuple = (5, 10);
Console.WriteLine(left == longTuple); // true

(long a, int b) longFirst = (5, 10);
(int a, long b) longSecond = (5, 10);
Console.WriteLine(longFirst == longSecond); // true

Имена элементов кортежей не участвуют в тестах на равенство. Если один из операндов является литералом кортежа с явными именами, компилятор генерирует предупреждение:

(int a, string b) pair    = (1, "Hello");
(int z, string y) another = (1, "Hello");

// имена элементов не участвуют
Console.WriteLine(pair == another); // true
// литерал содержит различные имена участников
Console.WriteLine(pair == (z: 1, y: "Hello")); // warning

Кортежи могут содержать вложенные кортежи. Функция проверки кортежей на равенство сравнивает "форму" каждого операнда по вложенным кортежам:

(int, (int, int)) nestedTuple = (1, (2, 3));
Console.WriteLine(nestedTuple == (1, (2, 3)) ); // true

"Подключение атрибутов к резервным полям для автоматически реализуемых свойств"

Целевое значение field устанавливает атрибут (Атрибуты) резервной переменной автоматически реализуемого свойства. Поддерживается следующий синтаксис:

[field: SomeThingAboutFieldAttribute]
public int SomeProperty { get; set; }

Атрибут SomeThingAboutFieldAttribute применяется к резервному полю, созданному компилятором для SomeProperty.


"Критерии для разрешения перегрузки метода in"

Устранена неоднозначность при добавлении модификатора аргумента in (C# 7.2):

static void M(S arg);
static void M(in S arg);

Перегрузка по значению (первая в примере) считается лучше, чем перегрузка по атрибуту "только для чтения".

Для вызова версии со ссылочным аргументом "только для чтения", необходимо при вызове метода указать модификатор in.


"Расширение переменных выражений в инициализаторах"

Синтаксис, позволяющий с версии C# 7.0 (C# 7.0) объявлять переменные out, поддерживает инициализаторы полей, инициализаторы свойств, инициализаторы конструктора и предложения запроса.

public class B
{
    // конструктор задаёт значение 'j'
    public B(int i, out int j)
        => j = i;
}

public class D : B
{
    // вызывается базовый конструктор
    public D(int i) : base(i, out var j)
    {
        Console.WriteLine($"значение 'j' равно {j}");
    }
}

"Улучшенный отбор потенциальных перегрузок"

Добавлено три правила разрешения перегрузок:

  1. Если группа методов содержит элементы экземпляра и статические элементы:
  • компилятор отклоняет все элементы экземпляра при вызове метода без экземпляра-получателя и вне контекста экземпляра.

  • компилятор отклоняет статические элементы, если метод был вызван с экземпляром-получателем.

Если получатель не указан, компилятор включает в статический контекст только статические элементы, а в противном случае – статические элементы и элементы экземпляра.

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

Статический контекст, в котором неявный this экземпляр-получатель нельзя использовать, включая тело членов, для которых this не задано, как например статические элементы, а также области, где this не может использоваться, такие как инициализаторы полей и инициализаторы конструкторов.

  1. Если группа методов содержит некоторые универсальные методы, у которых аргументы типа не удовлетворяют ограничениям, такие элементы удаляются из набора кандидатов.

  2. При преобразовании группы методов из набора удаляются методы-кандидаты, у которых возвращаемый тип не соответствует возвращаемому типу делегата.


НОВЫЕ ПАРАМЕТРЫ КОМПИЛЯТОРА

"Параметр компилятора publicsign"

Параметр компилятора -publicsign указывает, что сборку нужно подписать открытым ключом, фактически не подписывая сборку, сборка помечается как подписанная (задаёт в сборке бит, который сообщает среде выполнения, что файл подписан).

Позволяет создавать подписанные сборки из проектов с открытым кодом с помощью открытого ключа.

С параметром -publicsign необходимо использовать параметр -keyfile или -keycontainer (каждый определяет открытый ключ). Параметры -publicsign и -delaysign – взаимоисключающие.

При таком подписывании в сборку добавляется открытый ключ, устанавливается флаг "подписано", хотя фактически сборка не подписывается закрытым ключом. Такой подход называют "фиктивным подписыванием" или "подписыванием OSS", применяемым на проектах с открытым исходным кодом.

Установка параметра в среде разработки Visual Studio:

  1. Открыть страницу свойств проекта.

  2. Изменить свойство Delay sign only.


"Параметр компилятора pathmap"

Параметр компилятора -pathmap определяет способ сопоставления физических путей с именами исходных путей, выводимыми компилятором, управляет исходными путями, которые компилятор записывает в PDB-файлы или для CallerFilePathAttribute.

-pathmap:path1=sourcePath1,path2=sourcePath2

Аргументы:

  • path1 – полный путь к исходным файлам в текущем окружении.

  • sourcePath1 – исходный путь подставляется вместо path1 в любых выходных файлах.

*разделить запятыми для указания нескольких сопоставленных исходных путей

Компилятор записывает исходный путь в выходные данные по следующим причинам:

  1. Исходный путь подставляется вместо аргумента, когда CallerFilePathAttribute применяется как необязательный параметр.

  2. Исходный путь внедряется как PDB-файл.

  3. Путь к PDB-файлу внедряется в PE-файл (переносимый исполняемый файл).

Этот параметр сопоставляет каждый физический путь на компьютере, где выполняется компилятор, с соответствующим путем, который должен быть записан в выходные файлы.

Компиляция t.cs в каталоге C:\work\tests и сопоставление этого

каталога с каталогом \publish в выходных данных:

csc -pathmap:C:\work\tests=\publish t.cs