Compartilhar via


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

Use o ref modificador ao declarar um tipo de estrutura. Você aloca instâncias de um ref struct tipo na pilha e elas não podem escapar para o heap gerenciado. Para garantir essa propriedade, o compilador limita o uso de tipos da ref struct seguinte maneira:

  • Você não pode usar um ref struct tipo de elemento como uma matriz.
  • Você não pode declarar um ref struct como o tipo de um campo em uma classe ou nãoref struct.
  • Você não pode box a ref struct to System.ValueType ou System.Object.
  • Você não pode capturar uma ref struct variável em uma expressão lambda ou em uma função local.
  • Antes do C# 13, você não pode usar ref struct variáveis em um async método. A partir do C# 13, uma variável ref struct não pode ser usada no mesmo bloco que a expressão await 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>.
  • Antes do C# 13, você não pode usar uma ref struct variável em iteradores. A partir do C# 13, tipos ref struct e locais ref podem ser usados ​​em iteradores, desde que não estejam em segmentos de código com a instrução yield return.
  • Antes do C# 13, um ref struct não pode implementar interfaces. A partir do C# 13, um struct ref pode implementar interfaces, mas deve seguir as regras de segurança de ref. Por exemplo, um tipo ref struct não pode ser convertido no tipo de interface porque isso requer uma conversão de boxing.
  • Antes do C# 13, um ref struct não pode ser um argumento de tipo. A partir do C# 13, um ref struct pode ser o argumento de tipo quando o parâmetro de tipo especifica o allows ref struct em sua cláusula where.

A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para recursos em visualizações públicas para a próxima versão do idioma.

A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.

Dica

Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.

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

Você pode declarar um ref campo 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 reatribuir esse campo usando o = ref operador somente dentro de um construtor ou acessadorinit. Você pode atribuir um valor com o operador = a qualquer momento permitido pelo modificador de acesso ao campo.
  • ref readonly: em nenhum momento, você não pode atribuir um valor com o = operador a esse campo. No entanto, você pode reatribuir o campo usando o = ref operador.
  • readonly ref readonly: você só pode reatribuir esse 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. Usando uma referência, uma Span<T> instância evita copiar o armazenamento ao qual se refere.

O padrão descartável

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 acessível, sem parâmetros e que tem um void tipo de retorno. Você pode usar a instrução ou declaração using com uma instância de um ref struct descartável.

A partir do C# 13, você também pode implementar IDisposable em tipos ref struct. No entanto, a resolução de sobrecarga prefere o padrão descartável ao método de interface. O compilador resolve para um IDisposable.Dispose método somente quando um método adequado Dispose não é encontrado.

Restrições para tipos ref struct que implementam uma interface

Essas restrições garantem que um ref struct tipo que implementa uma interface siga as regras de segurança ref necessárias.

  • Você não pode converter uma ref struct instância de uma interface que ela implementa. Essa restrição inclui a conversão implícita quando você usa um ref struct tipo como argumento e o parâmetro é um tipo de interface. A conversão resulta em uma conversão de boxing, que viola a segurança de ref. Um ref struct pode declarar métodos como declarações de interface explícitas. No entanto, você pode acessar esses métodos somente de métodos genéricos em que os tipos de parâmetro allows ref struct de tipo.
  • Um ref struct que implementa uma interface deve implementar todos os membros de instância da interface. O ref struct deve implementar membros de instância mesmo quando a interface inclui uma implementação padrão.

O compilador impõe essas restrições. Se você escrever tipos ref struct que implementam interfaces, cada nova atualização poderá incluir novos membros de interface padrão. Até que você forneça uma implementação para quaisquer novos métodos de instância, seu aplicativo não será compilado. Você não pode fornecer uma implementação específica para um método de interface static com uma implementação padrão.

Importante

A implementação de uma interface com um ref struct tipo apresenta o potencial para alterações posteriores de quebra de origem e de quebra binária. A interrupção ocorre se uma ref struct interface é implementada definida em outro assembly e esse assembly fornece uma atualização que adiciona membros padrão a essa interface.

A quebra de origem ocorre quando você recompila o ref struct: ele deve implementar o novo membro, mesmo que haja uma implementação padrão.

A interrupção binária ocorrerá se você atualizar o assembly externo sem recompilar o ref struct tipo e o código atualizado chamar a implementação padrão do novo método. O runtime gera uma exceção quando o membro padrão é acessado.

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