Tipos de valor (Referencia de C#)

Los tipos de valor y los tipos de referencia son las dos categorías principales de tipos de C#. Una variable de un tipo de valor contiene una instancia del tipo. Esto difiere de una variable de un tipo de referencia, que contiene una referencia a una instancia del tipo. De forma predeterminada, al asignar, pasar un argumento a un método o devolver el resultado de un método, se copian los valores de variable. En el caso de las variables de tipo de valor, se copian las instancias de tipo correspondientes. En el ejemplo siguiente se muestra ese comportamiento:

using System;

public struct MutablePoint
{
    public int X;
    public int Y;

    public MutablePoint(int x, int y) => (X, Y) = (x, y);

    public override string ToString() => $"({X}, {Y})";
}

public class Program
{
    public static void Main()
    {
        var p1 = new MutablePoint(1, 2);
        var p2 = p1;
        p2.Y = 200;
        Console.WriteLine($"{nameof(p1)} after {nameof(p2)} is modified: {p1}");
        Console.WriteLine($"{nameof(p2)}: {p2}");

        MutateAndDisplay(p2);
        Console.WriteLine($"{nameof(p2)} after passing to a method: {p2}");
    }

    private static void MutateAndDisplay(MutablePoint p)
    {
        p.X = 100;
        Console.WriteLine($"Point mutated in a method: {p}");
    }
}
// Expected output:
// p1 after p2 is modified: (1, 2)
// p2: (1, 200)
// Point mutated in a method: (100, 200)
// p2 after passing to a method: (1, 200)

Como se muestra en el ejemplo anterior, las operaciones en una variable de tipo de valor solo afectan a esa instancia del tipo de valor, almacenado en la variable.

Si un tipo de valor contiene un miembro de datos de un tipo de referencia, solo se copia la referencia a la instancia del tipo de referencia al copiar una instancia de tipo de valor. Tanto la instancia de tipo de valor original como la copia tienen acceso a la misma instancia de tipo de referencia. En el ejemplo siguiente se muestra ese comportamiento:

using System;
using System.Collections.Generic;

public struct TaggedInteger
{
    public int Number;
    private List<string> tags;

    public TaggedInteger(int n)
    {
        Number = n;
        tags = new List<string>();
    }

    public void AddTag(string tag) => tags.Add(tag);

    public override string ToString() => $"{Number} [{string.Join(", ", tags)}]";
}

public class Program
{
    public static void Main()
    {
        var n1 = new TaggedInteger(0);
        n1.AddTag("A");
        Console.WriteLine(n1);  // output: 0 [A]

        var n2 = n1;
        n2.Number = 7;
        n2.AddTag("B");

        Console.WriteLine(n1);  // output: 0 [A, B]
        Console.WriteLine(n2);  // output: 7 [A, B]
    }
}

Nota

Para que el código sea menos propenso a errores y más sólido, defina y use tipos de valor inmutables. En este artículo se usan tipos de valor mutables solo con fines de demostración.

Clases de tipos de valor y restricciones de tipo

Un tipo de valor puede ser de una de las dos clases siguientes:

  • un tipo de estructura, que encapsula los datos y la funcionalidad relacionada;
  • un tipo de enumeración, que se define mediante un conjunto de constantes con nombre y representa una opción o una combinación de opciones.

Un tipo de valor que admite valores NULL T? representa todos los valores de su tipo de valor subyacente T y un valor NULL adicional. No se puede asignar null a una variable de un tipo de valor, a menos que sea un tipo de valor que acepte valores NULL.

Puede usar la restricción struct para especificar que un parámetro de tipo es un tipo de valor que no acepta valores NULL. Los tipos de estructura y enumeración satisfacen la restricción struct. A partir C# 7.3, puede usar System.Enum en una restricción de clase base (conocida como la restricción de enumeración) para especificar que un parámetro de tipo es un tipo de enumeración.

Tipos de valor integrados

C# proporciona los siguientes tipos de valor integrados, también conocidos como tipos simples:

Todos los tipos simples son tipos de estructuras y se diferencian de otros tipos de estructuras en que permiten determinadas operaciones adicionales:

  • Se pueden usar literales para proporcionar un valor de un tipo simple. Por ejemplo, 'A' es un literal del tipo char y 2001 es un literal del tipo int.

  • Puede declarar constantes de los tipos simples con la palabra clave const. No es posible tener constantes de otros tipos de estructuras.

  • Las expresiones constantes, cuyos operandos son todas constantes de los tipos simples, se evalúan en tiempo de compilación.

A partir de C# 7.0, C# admite tuplas de valor. Una tupla de valor es un tipo de valor, pero no un tipo simple.

Especificación del lenguaje C#

Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:

Vea también