ref
Типы структур (справочник по C#)
Модификатор можно использовать ref
в объявлении типа структуры. Экземпляры ref struct
типа выделяются в стеке и не могут экранироваться в управляемую кучу. Чтобы убедиться, что компилятор ограничивает использование ref struct
типов следующим образом:
- Не
ref struct
может быть типом элемента массива. - Не
ref struct
может быть объявленным типом поля класса или не-ref struct
. - Не
ref struct
удается включить System.ValueType в поле или System.Object. - Переменная
ref struct
не может быть записана в лямбда-выражении или локальной функции. - До C# 13
ref struct
переменные нельзя использовать в методеasync
. Начиная с C# 13 переменнаяref struct
не может использоваться в том же блоке, чтоawait
и выражение в методеasync
. Однако переменные можно использоватьref struct
в синхронных методах, например в методах, возвращающих Task или Task<TResult>. - До C# 13
ref struct
переменная не может использоваться в итераторах. Начиная с C# 13,ref struct
типы иref
локальные типы можно использовать в итераторах, если они не содержатся в сегментах кода с инструкциейyield return
. - До C# 13
ref struct
не удается реализовать интерфейсы. Начиная с C# 13 структураref
может реализовывать интерфейсы, но должна соответствовать правилам безопасности ссылок . Например, тип нельзя преобразовать в тип интерфейса,ref struct
так как для этого требуется преобразование бокса. - До C# 13
ref struct
не может быть аргументом типа. Начиная с C# 13, аргумент типа может быть аргументом типа,ref struct
если параметр типа указываетallows ref struct
в предложении.where
Как правило, вы определяете ref struct
тип, если требуется тип, который также включает элементы ref struct
данных типов:
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
Чтобы объявить как ref struct
readonly
, объедините readonly
модификаторы и ref
модификаторы в объявлении типа ( readonly
модификатор должен прийти перед модификатором ref
):
public readonly ref struct ConversionRequest
{
public ConversionRequest(double rate, ReadOnlySpan<double> values)
{
Rate = rate;
Values = values;
}
public double Rate { get; }
public ReadOnlySpan<double> Values { get; }
}
В .NET примеры ref struct
: System.Span<T> и System.ReadOnlySpan<T>.
ref
Поля
Начиная с C# 11, можно объявить ref
поле в виде ref struct
следующего примера:
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
Поле ref
может иметь null
значение. Unsafe.IsNullRef<T>(T) Используйте метод, чтобы определить, является null
ли ref
поле.
Модификатор можно применить к ref
полю readonly
следующим образом:
readonly ref
: можно переназначить такое поле= ref
только в конструкторе или методеinit
доступа. Можно назначить значение оператору=
в любой точке, разрешенной модификатором доступа к полю.ref readonly
: в любой момент невозможно назначить значение оператору=
для такого поля. Однако можно переназначить поле оператором= ref
.readonly ref readonly
: можно переназначить такое поле только в конструкторе или методеinit
доступа. В любой момент нельзя назначить значение полю.
Компилятор гарантирует, что ссылка, хранящуюся в ref
поле, не выходит за пределы его ссылки.
Функция ref
полей обеспечивает безопасную реализацию таких типов:System.Span<T>
public readonly ref struct Span<T>
{
internal readonly ref T _reference;
private readonly int _length;
// Omitted for brevity...
}
Тип Span<T>
сохраняет ссылку, через которую он обращается к смежным элементам в памяти. Использование ссылки позволяет Span<T>
экземпляру избежать копирования хранилища, на которое он ссылается.
Шаблон, допускающий удаление
Можно определить утилизированную ref struct
. Для этого убедитесь, что ref struct
шаблон подходит для удаления. То есть он имеет метод экземпляра Dispose
, который доступен, без параметров и имеет тип возвращаемого void
значения. Вы можете использовать инструкцию using или объявление с экземпляром удаленного объекта ref struct
.
Начиная с C# 13, можно также реализовать IDisposable ref struct
типы. Однако разрешение перегрузки предпочитает уменяемый шаблон для метода интерфейса. Компилятор разрешает IDisposable.Dispose
метод только в том случае, если подходящий Dispose
метод не найден.
Ограничения для ref struct
типов, реализующих интерфейс
Эти ограничения гарантируют, что ref struct
тип, реализующий интерфейс, подчиняется необходимым правилам безопасности ссылок.
- Невозможно
ref struct
преобразовать его в экземпляр интерфейса, который он реализует. Это ограничение включает неявное преобразование при использованииref struct
типа в качестве аргумента, если параметр является типом интерфейса. Преобразование приводит к преобразованию бокса, которое нарушает безопасность ссылок. - Объект
ref struct
, реализующий интерфейс , должен реализовывать все члены интерфейса. Необходимоref struct
реализовать элементы, в которых интерфейс включает реализацию по умолчанию.
Компилятор применяет эти ограничения. При написании ref struct
типов, реализующих интерфейсы, каждое новое обновление может включать новые члены интерфейса по умолчанию. Пока вы не предоставите реализацию для этих новых методов, приложение не будет компилировать.
Внимание
Реализация ref struct
интерфейса включает потенциал для последующих исходных и двоичных изменений. Разрыв возникает, если ref struct
интерфейс, определенный в другой сборке, и эта сборка предоставляет обновление, которое добавляет элементы по умолчанию в этот интерфейс.
Исходный разрыв происходит при повторной компиляции ref struct
: он должен реализовать новый член, даже если существует реализация по умолчанию.
Двоичный разрыв происходит при обновлении внешней сборки без повторной компиляции ref struct
типа , а обновленный код вызывает реализацию нового метода по умолчанию. Среда выполнения создает исключение при доступе к члену по умолчанию.
Спецификация языка C#
Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:
Дополнительные сведения о ref
полях см. в заметке о улучшении структуры низкого уровня.