Partilhar via


ref tipos de estrutura (referência C#)

Use o ref modificador ao declarar um tipo de estrutura. Alocas instâncias de um ref struct tipo na pilha, e elas não podem escapar para a pilha gerida. Para garantir esta propriedade, o compilador limita o uso dos ref struct tipos da seguinte forma:

  • Não podes usar a ref struct como elemento de um array.
  • Não podes declarar a ref struct como o tipo de campo numa disciplina ou num não-ref struct.
  • Não podes alinear a ref struct para System.ValueType ou System.Object.
  • Não se pode capturar uma ref struct variável numa expressão lambda ou numa função local.
  • Antes de C# 13, não podes usar ref struct variáveis num 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 de C# 13, não se pode usar uma ref struct variável nos 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.

A referência da linguagem C# documenta a versão mais recentemente lançada da linguagem C#. Contém também documentação inicial para funcionalidades em pré-visualizações públicas para o próximo lançamento linguístico.

A documentação identifica qualquer funcionalidade introduzida pela primeira vez nas últimas três versões da língua ou em pré-visualizações públicas atuais.

Sugestão

Para saber quando uma funcionalidade foi introduzida pela primeira vez em C#, consulte o artigo sobre o histórico de versões da linguagem C#.

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

Pode declarar um ref campo em , ref structcomo mostra o exemplo seguinte:

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: Pode reatribuir este campo usando o = ref operador apenas dentro de um construtor ou acessórioinit. Você pode atribuir um valor com o = operador em qualquer ponto permitido pelo modificador de acesso ao campo.
  • ref readonly: Em qualquer momento, não pode atribuir um valor com o = operador a este campo. No entanto, podes reatribuir o campo por referência usando o = ref operador.
  • readonly ref readonly: Só pode reatribuir este campo por referência num construtor ou num init acessório. 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. Ao usar uma referência, uma Span<T> instância evita copiar o armazenamento a que 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 void tipo de 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 somente quando um método adequado Dispose não é encontrado.

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

Estas restrições garantem que um ref struct tipo que implementa uma interface cumpre as regras necessárias de segurança de referência .

  • Não podes converter a ref struct numa instância de uma interface que ele implementa. Esta restrição inclui a conversão implícita quando se usa um ref struct tipo como argumento e 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. Um ref struct pode declarar métodos como declarações de interface explícitas. No entanto, só pode aceder a esses métodos a partir de métodos genéricos onde os tipos de parâmetro allows ref struct de tipo.
  • Um ref struct que implementa uma interface deve implementar todos os membros da interface da instância. O ref struct deve implementar membros da instância mesmo quando 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é forneceres uma implementação para quaisquer novos métodos de instância, a tua aplicação não compila. Não é possível fornecer uma implementação específica para um método de interface static com uma implementação padrão.

Importante

Implementar uma interface com um ref struct tipo introduz o potencial para alterações futuras que quebram o código-fonte e o binário. A quebra ocorre se a ref struct implementar uma interface definida noutra assembleia, e essa montagem fornecer uma atualização que adiciona membros por defeito a essa interface.

A quebra de origem acontece quando se recompila o ref struct: Deve implementar o novo membro, mesmo que exista uma implementação padrão.

A quebra binária acontece se atualizar o assembly externo sem recompilar o ref structtipo 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