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 umasync
método. A partir do C# 13, umaref struct
variável não pode ser usada no mesmo bloco que aawait
expressão em umasync
método. No entanto, você pode usarref 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 eref
locais podem ser usados em iteradores, desde que não estejam em segmentos de código com ayield return
instrução. - Antes do C# 13, um
ref struct
não pode implementar interfaces. A partir do C# 13, umref
struct pode implementar interfaces, mas deve aderir às regras de segurança ref. Por exemplo, umref 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, aref struct
pode ser o argumento type quando o parâmetro type especifica oallows ref struct
em suawhere
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 uminit
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 acessadorinit
. 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 umref 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. Osref 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.