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


ref Типы структур (справочник по C#)

ref Используйте модификатор при объявлении типа структуры. Вы выделяете экземпляры ref struct типа в стеке, и они не могут экранироваться в управляемую кучу. Чтобы обеспечить это свойство, компилятор ограничивает использование ref struct типов следующим образом:

  • Нельзя использовать ref struct в качестве типа элемента массива.
  • Нельзя объявить ref struct в качестве типа поля в классе или не-ref struct.
  • Вы не можете ставить поле для ref struct или System.ValueTypeSystem.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

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

Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.

Подсказка

Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей по журналу версий языка C#.

Как правило, вы определяете ref struct тип, если требуется тип, который также включает элементы ref struct данных типов:

public ref struct CustomRef
{
    public bool IsValid;
    public Span<int> Inputs;
    public Span<int> Outputs;
}

Чтобы объявить как ref structreadonly, объедините 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 Поля

Вы можете объявить 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) Используйте метод, чтобы определить, является refли null поле.

Модификатор можно применить к readonly полю ref следующим образом:

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

Ограничения для ref struct типов, реализующих интерфейс

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

  • Невозможно преобразовать ref struct экземпляр интерфейса, который он реализует. Это ограничение включает неявное преобразование при использовании ref struct типа в качестве аргумента, а параметр — тип интерфейса. Преобразование приводит к преобразованию бокса, которое нарушает безопасность ссылок. ref struct может объявлять методы как явные объявления интерфейса. Однако доступ к этим методам можно получить только из универсальных методов, в которых типы параметров allows ref struct типа.
  • ref struct, реализующий интерфейс , должен реализовать все экземплярные члены интерфейса. ref struct должен реализовывать членов экземпляра, даже если интерфейс включает реализацию по умолчанию.

Компилятор применяет эти ограничения. При написании ref struct типов, реализующих интерфейсы, каждое новое обновление может включать новые члены интерфейса по умолчанию. Пока вы не предоставите реализацию для любых новых методов экземпляра, приложение не компилируется. Нельзя предоставить конкретную реализацию для метода интерфейса static с реализацией по умолчанию.

Внимание

Реализация интерфейса с типом ref struct представляет потенциал для последующих критических и двоичных изменений. Разрыв возникает, если ref struct интерфейс, определенный в другой сборке, и эта сборка предоставляет обновление, которое добавляет элементы по умолчанию в этот интерфейс.

Исходный разрыв происходит при повторной компиляции ref struct: он должен реализовать новый член, даже если существует реализация по умолчанию.

Двоичный разрыв происходит при обновлении внешней сборки без повторной компиляции ref struct типа , а обновленный код вызывает реализацию нового метода по умолчанию. Среда выполнения создает исключение при доступе к члену по умолчанию.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

Дополнительные сведения о ref полях см. в заметке о улучшении структуры низкого уровня.

См. также