Tipos de valor (referência C#)

Tipos de valor e tipos de referência são as duas principais categorias de tipos de C#. Uma variável de um tipo de valor contém uma instância do tipo. Isso difere de uma variável de um tipo de referência, que contém uma referência a uma instância do tipo. Por padrão, na atribuição, passando um argumento para um método e retornando um resultado de método, os valores das variáveis são copiados. No caso de variáveis de tipo valor, as instâncias de tipo correspondentes são copiadas. O exemplo a seguir demonstra esse comportamento:

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 mostra o exemplo anterior, as operações em uma variável de tipo de valor afetam apenas essa instância do tipo de valor, armazenada na variável.

Se um tipo de valor contiver um membro de dados de um tipo de referência, somente a referência à instância do tipo de referência será copiada quando uma instância de tipo de valor for copiada. Tanto a instância de tipo de valor de cópia quanto a de original têm acesso à mesma instância de tipo de referência. O exemplo a seguir demonstra esse comportamento:

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 tornar seu código menos propenso a erros e mais robusto, defina e use tipos de valor imutáveis. Este artigo usa tipos de valor mutáveis apenas para fins de demonstração.

Tipos de tipos de valor e restrições de tipo

Um tipo de valor pode ser um dos dois tipos a seguir:

  • um tipo de estrutura, que encapsula dados e funcionalidades relacionadas
  • Um tipo de enumeração, que é definido por um conjunto de constantes nomeadas e representa uma escolha ou uma combinação de opções

Um tipoT? de valor anulável representa todos os valores de seu tipo T de valor subjacente e um valor nulo adicional. Não é possível atribuir null a uma variável de um tipo de valor, a menos que seja um tipo de valor anulável.

Você pode usar a struct restrição para especificar que um parâmetro type é um tipo de valor não anulável. Ambos os tipos de estrutura e enumeração satisfazem a struct restrição. Você pode usar System.Enum em uma restrição de classe base (que é conhecida como a restrição de enum) para especificar que um parâmetro type é um tipo de enumeração.

Tipos de valor incorporados

O C# fornece os seguintes tipos de valor internos, também conhecidos como tipos simples:

Todos os tipos simples são tipos de estrutura e diferem de outros tipos de estrutura na medida em que permitem certas operações adicionais:

  • Você pode usar literais para fornecer um valor de um tipo simples. Por exemplo, 'A' é um literal do tipo char e 2001 é um literal do tipo int.

  • Você pode declarar constantes dos tipos simples com a palavra-chave const . Não é possível ter constantes de outros tipos de estrutura.

  • Expressões constantes, cujos operandos são todas constantes dos tipos simples, são avaliadas em tempo de compilação.

Uma tupla de valor é um tipo de valor, mas não um tipo simples.

Especificação da linguagem C#

Para obter mais informações, consulte as seguintes seções da especificação da linguagem C#:

Consulte também