Поделиться через


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 типы. Однако разрешение перегрузки предпочитает уменяемый шаблон для метода интерфейса. Компилятор разрешает методу только в том случаеDispose, если подходящий IDisposable.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 полях см. в заметке о улучшении структуры низкого уровня.

См. также