Partilhar via


Introdução aos tipos de registo em C#

Um registro em C# é uma classe ou 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 principal é armazenar dados. Estes membros incluem uma sobrecarga de ToString() e membros que apoiam a igualdade de valores.

Quando usar registros

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

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

Igualdade de valores

Para registros, igualdade de valor significa que duas variáveis de um tipo de registro são iguais se os tipos corresponderem e todos os valores de propriedade e campo forem comparados iguais. Para outros tipos de referência, como classes, igualdade significa igualdade de referência por padrão, a menos que de igualdade de valor tenha sido implementada. Ou seja, duas variáveis de um tipo de classe são iguais se se referirem ao mesmo objeto. Métodos e operadores que determinam a igualdade de duas instâncias de registro usam a 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 utiliza apenas uma instância de um tipo de entidade para o que é, conceitualmente, uma entidade só. 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 valores de campo de um objeto depois que ele é instanciado. A imutabilidade pode ser útil quando você precisa de um tipo para ser thread-safe ou você está dependendo de um código hash que permanece 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. Entity Framework Core, por exemplo, não oferece suporte à atualização com tipos de entidade imutáveis.

Como os registros diferem de classes e estruturas

A mesma sintaxe que declara e instancia classes ou estruturas pode ser usada com registos. Basta substituir a palavra-chave class pela record, ou usar record struct em vez de struct. Da mesma forma, a mesma sintaxe para expressar relações de herança é suportada por classes de registro. Os registros diferem das classes das seguintes maneiras:

  • Você pode usar parâmetros posicionais num construtor primário para criar e instanciar um tipo com propriedades imutáveis.
  • Os mesmos métodos e operadores que indicam a igualdade ou desigualdade de referência em classes (como Object.Equals(Object) e ==), indicam valor igualdade ou desigualdade nos registros.
  • Você pode usar uma expressão with para criar uma cópia de um objeto imutável com novos valores nas 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 suas propriedades públicas.
  • 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.

Record structs diferem de structs na medida em que o compilador sintetiza os métodos para igualdade, e ToString. O compilador sintetiza um método Deconstruct para estruturas de registro posicionais.

O compilador sintetiza uma propriedade init-only pública para cada parâmetro do construtor primário num record class. Em um record struct, o compilador sintetiza uma propriedade pública de leitura e escrita. O compilador não cria propriedades para os parâmetros primários do construtor nos tipos class e struct que não incluem o 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, imprime o nome do tipo e os valores da 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 exemplo a seguir demonstra a igualdade de valor nos 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 exemplo a seguir 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, consulte Records (referência 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 do C#.