Tipos de estrutura ref (referência de C#)

Você pode usar o modificador ref na declaração de um tipo de estrutura. As instâncias de um tipo ref struct são alocadas na pilha e não podem escapar para o heap gerenciado. Para garantir isso, o compilador limita o uso de tipos ref struct da seguinte maneira:

  • Um ref struct não pode ser o tipo de elemento de uma matriz.
  • Um ref struct não pode ser um tipo declarado de um campo de uma classe ou um não ref struct.
  • Um ref struct não pode implementar interfaces.
  • Um ref struct não pode ser demarcado para System.ValueType ou System.Object.
  • Um ref struct não pode ser um argumento de tipo.
  • Uma variável ref struct não pode ser capturada por uma expressão lambda ou uma função local.
  • Uma variável ref struct não pode ser usada em um método async. No entanto, você pode usar variáveis ref struct em métodos síncronos, por exemplo, em métodos que retornam Task ou Task<TResult>.
  • Uma variável ref struct não pode ser usada em iteradores.

Você pode definir um ref struct descartável. Para fazer isso, verifique se um ref struct se encaixa no padrão descartável. Ou seja, ele tem um método de instância Dispose, que é acessível, sem parâmetros e tem um tipo void de retorno. Você pode usar a instrução ou declaração using com uma instância de um ref struct descartável.

Normalmente, você define um tipo de ref struct quando precisa de um tipo que também inclua membros de dados de tipos de ref struct:

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

Para declarar um ref struct como readonly, combine os modificadores readonly e ref na declaração de tipo (o modificador readonly deve vir antes do 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; }
}

No .NET, exemplos de um ref struct são System.Span<T> e System.ReadOnlySpan<T>.

Campos ref

A partir do C# 11, você pode declarar um campo ref em um ref struct, como mostra o exemplo a seguir:

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;
    }
}

Um campo ref pode ter o valor null. Use o método Unsafe.IsNullRef<T>(T) para determinar se um campo ref é null.

Você pode aplicar o modificador readonly a um campo ref das seguintes maneiras:

  • readonly ref: você pode fazer reatribuição de ref desse campo com o operador = ref somente dentro de um construtor ou um init acessador. Você pode atribuir um valor com o operador = a qualquer momento permitido pelo modificador de acesso ao campo.
  • ref readonly: você nunca poderá atribuir um valor com o operador = a esse campo. No entanto, você pode fazer reatribuição de ref de um campo com o operador = ref.
  • readonly ref readonly: você só pode fazer reatribuição de ref desse campo em um construtor ou acessador init. Em nenhum momento, você não pode atribuir um valor ao campo.

O compilador garante que uma referência armazenada no campo ref não sobreviva ao valor ao qual se refere.

O recurso de campos ref permite uma implementação segura de tipos como System.Span<T>:

public readonly ref struct Span<T>
{
    internal readonly ref T _reference;
    private readonly int _length;

    // Omitted for brevity...
}

O tipo Span<T> armazena uma referência por meio da qual acessa os elementos contíguos na memória. O uso de uma referência permite que uma instância Span<T> evite copiar o armazenamento ao qual se refere.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Para obter mais informações sobre os campos ref, confira a nota de proposta Aprimoramentos de struct de baixo nível.

Confira também