Tipos de estructura ref
(referencia de C#)
Puede usar el modificador ref
en la declaración de un tipo de estructura. Las instancias de un tipo ref struct
se asignan en la pila y no pueden escapar al montón administrado. Para asegurarse de esto, el compilador limita el uso de tipos ref struct
de la siguiente manera:
ref struct
no puede ser el tipo de elemento de una matriz.ref struct
no puede ser un tipo declarado de un campo de una clase o un elemento que no searef struct
.- A
ref struct
no se le puede aplicar la conversión boxing a System.ValueType ni System.Object. - Una variable de
ref struct
no se puede capturar con una expresión lambda ni una función local. - Antes de C# 13,
ref struct
las variables no se pueden usar en unasync
método . A partir de C# 13, no se puede usar una variableref struct
en el mismo bloque que la expresiónawait
en un métodoasync
. Sin embargo, puede usar variables deref struct
en métodos sincrónicos, como los que devuelven Task o Task<TResult>. - Antes de C# 13, no se puede usar una variable
ref struct
en iteradores. A partir de C# 13, se pueden usar tiposref struct
y localesref
en iteradores, siempre que no estén en segmentos de código con la instrucciónyield return
. - Antes de C# 13, un
ref struct
no puede implementar interfaces. A partir de C# 13, una estructuraref
puede implementar interfaces, pero debe cumplir las reglas de seguridad de ref. Por ejemplo, un tiporef struct
no se puede convertir al tipo de interfaz porque requiere una conversión boxing. - Antes de C# 13, un
ref struct
no puede ser un argumento de tipo. A partir de C# 13, unref struct
puede ser el argumento type cuando el parámetro type especifica elallows ref struct
en su cláusulawhere
.
Normalmente, se define un tipo ref struct
cuando se necesita un tipo que también incluya miembros de datos de tipos ref struct
:
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
Para declarar ref struct
como readonly
, combine los modificadores readonly
y ref
en la declaración de tipos (el modificador readonly
debe ir delante del modificador 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; }
}
En .NET, System.Span<T> y System.ReadOnlySpan<T> son ejemplos de una clase ref struct
.
Campos ref
A partir de C# 11, puede declarar un campo ref
en un elemento ref struct
, como se muestra en el siguiente ejemplo:
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;
}
}
Un campo ref
puede tener el valor null
. Use el método Unsafe.IsNullRef<T>(T) para determinar si un campo ref
es null
.
Puede aplicar el modificador readonly
a un campo ref
de varias formas:
readonly ref
: puede aplicar una asignación de referencia al campo con el operador= ref
solo dentro de un constructor o un descriptor de accesoinit
. Puede asignar un valor con el operador=
en cualquier punto permitido por el modificador de acceso del campo.ref readonly
: no se puede asignar un valor con el operador=
al campo en ningún momento. Sin embargo, puede aplicar una asignación de referencia a un campo con el operador= ref
.readonly ref readonly
: solo puede aplicar una asignación de referencia a un campo en un constructor o un descriptor de accesoinit
. No puede asignar un valor al campo en ningún momento.
El compilador se asegura de que una referencia almacenada en un campo ref
no sobreviva al valor al que hace referencia.
La característica de campos ref
permite una implementación 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...
}
El tipo Span<T>
almacena una referencia a través de la cual accede a los elementos contiguos en memoria. El uso de una referencia permite a una instancia Span<T>
evitar copiar el almacenamiento al que hace referencia.
El patrón descartable
Puede definir un elemento ref struct
descartable. Para ello, asegúrese de que el elemento ref struct
se ajuste al patrón descartable. Es decir, tiene una instancia o un método Dispose
de extensión, que es accesible, no tiene parámetros y tiene un tipo de valor devuelto void
. Puede usar la instrucción using o declaración con una instancia de un elemento descartable ref struct
.
A partir de C# 13, también puede implementar el IDisposable en tipos ref struct
. Sin embargo, la resolución de sobrecarga prefiere el patrón descartable para el método de interfaz. El compilador se resuelve en un método IDisposable.Dispose
solo si no encuentra un método Dispose
adecuado.
Restricciones para los tipos ref struct
que implementan una interfaz
Estas restricciones garantizan que un tipo ref struct
que implemente una interfaz cumpla las reglas de seguridad ref necesarias.
- Un
ref struct
no se puede convertir en una instancia de una interfaz que implementa. Esta restricción incluye la conversión implícita cuando se usa un tiporef struct
como argumento cuando el parámetro es un tipo de interfaz. La conversión da como resultado una conversión boxing, que infringe la seguridad ref. - Un
ref struct
que implementa una interfaz debe implementar todos los miembros de la interfaz.ref struct
debe implementar miembros en los que la interfaz incluya una implementación predeterminada.
El compilador aplica estas restricciones. Si escribe tipos ref struct
que implementan interfaces, cada nueva actualización puede incluir nuevos miembros de interfaz predeterminados. Hasta que proporcione una implementación para estos nuevos métodos, la aplicación no se compilará.
Importante
Un ref struct
que implementa una interfaz incluye la posibilidad de cambios posteriores de interrupción del origen y de interrupción binaria. La interrupción se produce si ref struct
implementa una interfaz definida en otro ensamblado y ese ensamblado proporciona una actualización que agrega miembros predeterminados a esa interfaz.
La interrupción de origen se produce cuando se vuelve a compilar ref struct
: debe implementar el nuevo miembro, aunque haya una implementación predeterminada.
La interrupción binaria se produce si actualiza el ensamblado externo sin volver a compilar el tipo ref struct
y el código actualizado llama a la implementación predeterminada del nuevo método. El tiempo de ejecución produce una excepción cuando se accede al miembro predeterminado.
especificación del lenguaje C#
Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:
Para obtener más información sobre los campos ref
, consulte la nota de propuesta de mejoras de estructura de bajo nivel.