Compartir a través de


Tipos de estructura ref (referencia de C#)

Use el ref modificador al declarar un tipo de estructura. Asigna instancias de un ref struct tipo en la pila y no pueden escapar al montón administrado. Para garantizar esta propiedad, el compilador limita el uso de ref struct tipos de la siguiente manera:

  • No se puede usar ref struct como el tipo de elemento de una matriz.
  • No se puede declarar ref struct como el tipo de un campo en una clase o un noref struct.
  • No se puede boxear en ref structSystem.ValueType o System.Object.
  • No se puede capturar una ref struct variable en una expresión lambda ni en una función local.
  • Antes de C# 13, no puede usar ref struct variables en un async método . A partir de C# 13, no se puede usar una variable ref struct en el mismo bloque que la expresión await en un método async. Sin embargo, puede usar variables de ref struct en métodos sincrónicos, como los que devuelven Task o Task<TResult>.
  • Antes de C# 13, no se puede usar una ref struct variable en iteradores. A partir de C# 13, se pueden usar tipos ref struct y locales ref en iteradores, siempre que no estén en segmentos de código con la instrucción yield return.
  • Antes de C# 13, un ref struct no puede implementar interfaces. A partir de C# 13, una estructura ref puede implementar interfaces, pero debe cumplir las reglas de seguridad de ref. Por ejemplo, un tipo ref 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, un ref struct puede ser el argumento type cuando el parámetro type especifica el allows ref struct en su cláusula where.

La referencia del lenguaje C# documenta la versión publicada más recientemente del lenguaje C#. También contiene documentación inicial sobre las características de las versiones preliminares públicas de la próxima versión del lenguaje.

La documentación identifica cualquier característica introducida por primera vez en las últimas tres versiones del idioma o en las versiones preliminares públicas actuales.

Sugerencia

Para buscar cuándo se introdujo por primera vez una característica en C#, consulte el artículo sobre el historial de versiones del lenguaje C#.

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, ref struct y System.Span<T> son ejemplos de una clase System.ReadOnlySpan<T>.

Campos ref

Puede declarar un ref campo en , ref structcomo se muestra en el ejemplo siguiente:

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 reasignar este campo mediante el = ref operador solo dentro de un constructor o un init descriptor de acceso. Puede asignar un valor con el operador = en cualquier punto permitido por el modificador de acceso del campo.
  • ref readonly: en cualquier momento, no se puede asignar un valor con el = operador a este campo. Sin embargo, puede volver a asignar el campo mediante el = ref operador .
  • readonly ref readonly: solo puede reasignar este campo en un constructor o un init descriptor de acceso. 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. Mediante el uso de una referencia, una Span<T> instancia evita 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 un método de instancia Dispose accesible, sin parámetros y tiene un void tipo de valor devuelto. 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 IDisposable.Dispose método solo cuando no se encuentra un método adecuado Dispose .

Restricciones para los tipos ref struct que implementan una interfaz

Estas restricciones garantizan que un ref struct tipo que implemente una interfaz siga las reglas de seguridad ref necesarias.

  • No se puede convertir en una ref struct instancia de una interfaz que implementa. Esta restricción incluye la conversión implícita cuando se usa un ref struct tipo como argumento y 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 puede declarar métodos como declaraciones de interfaz explícitas. Sin embargo, solo puede acceder a esos métodos desde métodos genéricos donde los tipos de parámetro allows ref struct de tipo.
  • Un ref struct que implementa una interfaz debe implementar todos los miembros de la interfaz de instancia. El ref struct debe implementar miembros de instancia incluso cuando la interfaz incluye 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 los nuevos métodos de instancia, la aplicación no se compila. No se puede proporcionar una implementación específica para un método de interfaz static con una implementación predeterminada.

Importante

La implementación de una interfaz con un ref struct tipo presenta 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 ref struct tipo 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.

Consulte también