Partilhar via


ref tipos de estrutura (referência C#)

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

  • A ref struct não pode ser o tipo de elemento de uma matriz.
  • A ref struct não pode ser um tipo declarado de um campo de uma classe ou um não-ref struct.
  • A ref struct não pode ser encaixotado para System.ValueType ou System.Object.
  • Uma ref struct variável não pode ser capturada em uma expressão lambda ou em uma função local.
  • Antes do C# 13,ref struct as variáveis não podiam ser usadas em um async método. A partir do C# 13, uma ref struct variável não pode ser usada no mesmo bloco que a await expressão em um async método. No entanto, você pode usar ref struct variáveis em métodos síncronos, por exemplo, em métodos que retornam Task ou Task<TResult>.
  • Antes do C# 13, uma ref struct variável não podia ser usada em iteradores. A partir do C# 13, ref struct tipos e ref locais podem ser usados em iteradores, desde que não estejam em segmentos de código com a yield return instrução.
  • Antes do C# 13, um ref struct não pode implementar interfaces. A partir do C# 13, um ref struct pode implementar interfaces, mas deve aderir às regras de segurança ref. Por exemplo, um ref struct tipo não pode ser convertido para o tipo de interface porque isso requer uma conversão de boxe.
  • Antes do C# 13, um ref struct não pode ser um argumento de tipo. A partir de C# 13, a ref struct pode ser o argumento type quando o parâmetro type especifica o allows ref struct em sua where cláusula.

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

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

Para declarar a ref struct como readonly, combine os readonly modificadores e ref na declaração de tipo (o readonly modificador deve vir antes do ref modificador):

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>.

ref campos

A partir do C# 11, 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 ref campo pode ter o null valor. Use o Unsafe.IsNullRef<T>(T) método para determinar se um ref campo é null.

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

  • readonly ref: Você pode ref reatribuir tal campo com o operador apenas dentro de = ref um construtor ou um init acessador. Você pode atribuir um valor com o = operador em qualquer ponto permitido pelo modificador de acesso ao campo.
  • ref readonly: A qualquer momento, você não pode atribuir um valor com o = operador a esse campo. No entanto, você pode ref reatribuir um campo com o = ref operador.
  • readonly ref readonly: Você só pode ref reatribuir tal campo em um construtor ou acessador init . A qualquer momento, não é possível atribuir um valor ao campo.

O compilador garante que uma referência armazenada em um ref campo não sobreviva ao seu referente.

O ref recurso de campos 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 Span<T> tipo armazena uma referência através da qual ele acessa os elementos contíguos na memória. O uso de uma referência permite que uma Span<T> instância evite copiar o armazenamento ao qual se refere.

O padrão descartável

Você pode definir um descartável ref struct. Para fazer isso, certifique-se de que 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 de void retorno. Você pode usar a instrução using ou declaração com uma instância de um descartável ref struct.

A partir do C# 13, você também pode implementar os IDisposable tipos on 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 apenas quando um método adequado Dispose não é encontrado.

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

Essas restrições garantem que um ref struct tipo que implementa uma interface obedeça às regras de segurança de referência necessárias.

  • Um ref struct não pode ser convertido em uma instância de uma interface que ele implementa. Essa restrição inclui a conversão implícita quando você usa um ref struct tipo como argumento quando o parâmetro é um tipo de interface. A conversão resulta em uma conversão de boxe, o que viola a segurança de ref.
  • A ref struct que implementa uma interface deve implementar todos os membros da interface. Os ref struct membros devem implementar onde a interface inclui uma implementação padrão.

O compilador impõe essas restrições. Se você escrever ref struct tipos que implementam interfaces, cada nova atualização pode incluir novos membros de interface padrão. Até que você forneça uma implementação para esses novos métodos, seu aplicativo não será compilado.

Importante

A ref struct que implementa uma interface inclui o potencial para alterações posteriores de quebra de código-fonte e de quebra binária. A quebra ocorre se um ref struct implementa uma interface definida em outro assembly e esse assembly fornece uma atualização que adiciona membros padrão a essa interface.

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

A quebra binária acontece 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 tempo de execução lança uma exceção quando o membro padrão é acessado.

Especificação da linguagem C#

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

Para obter mais informações sobre ref campos, consulte a nota da proposta de melhorias de estrutura de baixo nível.

Consulte também