Compartilhar via


Introdução aos tipos de registro em C#

Um registro em C# é uma classe ou um struct que fornece sintaxe e comportamento especiais para trabalhar com modelos de dados. O modificador record instrui o compilador a sintetizar membros que são úteis para tipos cuja função primária é armazenar dados. Esses membros incluem uma sobrecarga de ToString() e membros que dão suporte à igualdade de valor.

Quando usar registros

Considere usar um registro no lugar de uma classe ou struct nos seguintes cenários:

  • Você deseja definir um modelo de dados que depende da igualdade de valor.
  • Você deseja definir um tipo para o qual os objetos são imutáveis.

Igualdade de valor

Para registros, a igualdade de valores significa que duas variáveis de um tipo de registro são iguais se os tipos corresponderem e todos os valores de propriedades e campos forem iguais. Para outros tipos de referência, como classes, igualdade significa igualdade de referência por padrão, a menos que a igualdade de valor tenha sido implementada. Ou seja, duas variáveis de um tipo de classe são iguais quando se referem ao mesmo objeto. Métodos e operadores que determinam a igualdade de duas instâncias de registro usam igualdade de valor.

Nem todos os modelos de dados funcionam bem com igualdade de valor. Por exemplo, o Entity Framework Core depende da igualdade de referência para garantir que ele use apenas uma instância de um tipo de entidade para o que é conceitualmente uma entidade. Por esse motivo, os tipos de registro não são apropriados para uso como tipos de entidade no Entity Framework Core.

Imutabilidade

Um tipo imutável é aquele que impede que você altere qualquer propriedade ou valor de campo de um objeto após ser instanciado. A imutabilidade pode ser útil quando você precisa que um tipo seja thread-safe ou que um código hash permaneça o mesmo em uma tabela de hash. Os registros fornecem sintaxe concisa para criar e trabalhar com tipos imutáveis.

A imutabilidade não é apropriada para todos os cenários de dados. O Entity Framework Core, por exemplo, não dá suporte à atualização com tipos de entidade imutáveis.

Como os registros diferem das classes e dos structs

A mesma sintaxe que declara e instancia classes ou structs pode ser usada com registros. Basta substituir a palavra-chave class por record, ou usar record struct em vez de struct. Da mesma forma, as classes de registro dão suporte à mesma sintaxe para expressar relações de herança. Os registros diferem das classes das seguintes maneiras:

  • Você pode usar parâmetros posicionais em um construtor primário para criar e instanciar um tipo com propriedades imutáveis.
  • Os mesmos métodos e operadores que indicam igualdade de referência ou desigualdade em classes (como Object.Equals(Object) e ==), indicam igualdade de valor ou desigualdade nos registros.
  • Você pode usar uma expressão with para criar uma cópia de um objeto imutável com novos valores em propriedades selecionadas.
  • O método ToString de um registro cria uma cadeia de caracteres formatada que mostra o nome do tipo de um objeto e os nomes e valores de todas as propriedades públicas dele.
  • Um registro pode herdar de outro registro. Um registro não pode herdar de uma classe, e uma classe não pode herdar de um registro.

Os structs de registro diferem dos structs, pois o compilador sintetiza os métodos de igualdade e ToString. O compilador sintetiza o método Deconstruct para structs de registro posicional.

O compilador sintetiza uma propriedade public init-only para cada parâmetro de construtor primário em um record class. Em um record struct, o compilador sintetiza uma propriedade pública de leitura/gravação. O compilador não cria propriedades para parâmetros de construtor primário em tipos class e struct que não incluem modificador record.

Exemplos

O exemplo a seguir define um registro público que usa parâmetros posicionais para declarar e instanciar um registro. Em seguida, ele imprime o nome do tipo e os valores de propriedade:


public record Person(string FirstName, string LastName);

public static class Program
{
    public static void Main()
    {
        Person person = new("Nancy", "Davolio");
        Console.WriteLine(person);
        // output: Person { FirstName = Nancy, LastName = Davolio }
    }

}

O seguinte exemplo demonstra a igualdade de valor em registros:

public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static class Program
{
    public static void Main()
    {
        var phoneNumbers = new string[2];
        Person person1 = new("Nancy", "Davolio", phoneNumbers);
        Person person2 = new("Nancy", "Davolio", phoneNumbers);
        Console.WriteLine(person1 == person2); // output: True

        person1.PhoneNumbers[0] = "555-1234";
        Console.WriteLine(person1 == person2); // output: True

        Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
    }
}

O seguinte exemplo demonstra o uso de uma expressão with para copiar um objeto imutável e alterar uma das propriedades:

public record Person(string FirstName, string LastName)
{
    public required string[] PhoneNumbers { get; init; }
}

public class Program
{
    public static void Main()
    {
        Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
        Console.WriteLine(person1);
        // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }

        Person person2 = person1 with { FirstName = "John" };
        Console.WriteLine(person2);
        // output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
        Console.WriteLine(person1 == person2); // output: False

        person2 = person1 with { PhoneNumbers = new string[1] };
        Console.WriteLine(person2);
        // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
        Console.WriteLine(person1 == person2); // output: False

        person2 = person1 with { };
        Console.WriteLine(person1 == person2); // output: True
    }
}

Para obter mais informações, confira Registros (referência de C#).

Especificação da Linguagem C#

Para obter mais informações, consulte a Especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso de C#.