A partir de C# 9, você pode usar o modificador de registro para definir um tipo de referência que ofereça funcionalidade embutida para encapsular dados. C# 10 permite que a sintaxe da classe de registro seja sinônimo para esclarecer tipos de referência, e permite que a estrutura de registro defina tipos de valor usando a mesma funcionalidade.
Casos de uso para registro em C#(ChatGPT responde):
O tipo de registro em C# é um recurso novo introduzido na versão mais recente. Pode ser usado em muitos cenários, incluindo, mas não se limitando aos seguintes:
Objeto de Dados Imutável: O tipo de registro é imutável, o que significa que, uma vez criado, seu valor de propriedade não pode ser modificado. Isso os torna ideais para representar estruturas de dados imutáveis, como objetos de transferência (DTOs) ou configurações de configuração. Objetos valor: O tipo de registro pode ser usado para representar objetos valor cuja igualdade é determinada com base em seus valores de atributo, e não na equivalência de referência. Isso os torna ideais para comparar e armazenar objetos de valor, como intervalos de datas, pontos de coordenadas e mais. Correspondência de Padrões: O tipo de registro pode ser usado em conjunto com o correspondimento de padrões, o que torna mais conveniente ao trabalhar com estruturas de dados complexas. Você pode usar a correspondência de padrões para verificar e extrair os valores dos atributos do objeto de registro, para que possa realizar a ação apropriada. Coleções Imutáveis: O tipo de registro pode ser usado com tipos de coleções imutáveis como ImmutableList, ImmutableDictionary, etc., para criar objetos de coleção imutáveis. Isso garante que o conteúdo da coleção não seja modificado, melhorando assim a confiabilidade e a segurança do código. Estes são apenas alguns dos casos de uso do tipo de registro, e você pode decidir se usa o tipo de registro com base nas suas necessidades específicas e na estrutura do código. Diferença entre disco e classe e estrutura
A sintaxe usada ao declarar e instanciar uma classe ou estrutura é a mesma que ao gravar uma operação. Basta substituir a palavra-chave class por record, ou usar record struct em vez de struct. De forma semelhante, a classe de registro suporta a mesma sintaxe para relações de herança. A diferença entre um registro e uma classe é a seguinte:
- Você pode usar parâmetros posicionais no construtor principal para criar e instanciar tipos com propriedades imutáveis.
- Métodos e operadores que indicam igualdade ou não igualdade de referência em classes (por exemplo, Object.Equals(Object) e ==) indicam igualdade ou não igualdade de valor no registro.
- Você pode usar a expressão with para criar uma cópia de um objeto imutável com um novo valor no atributo selecionado.
- O método ToString do registro cria uma string de formato que exibe o nome do tipo do objeto e os nomes e valores de todas as suas propriedades comuns.
- Um registro pode ser herdado de outro registro. Mas registros não podem ser herdados de classes, nem classes podem ser herdadas de registros.
- A diferença entre a estrutura do registro e a estrutura é que o compilador sintetiza métodos para determinar igualdade e ToString. O compilador sintetiza o método Deconstruct para a estrutura do registro de posição.
O compilador sintetiza uma propriedade comum de apenas inicialização para cada parâmetro principal do construtor na classe de registro. Em um registro de registro, o compilador sintetiza propriedades públicas de leitura/escrita. O compilador não cria propriedades para os argumentos principais do construtor nos tipos class e struct que não contêm o modificador de registro.
registro
Tipo de referência de classe de registro (padrão: a classe pode ser omitida) Tipo de valor de struct de registro
Açúcar gramatical de registro
Na verdade, o recorde é issoSintaxe sugar, e o resultado final é código de classe ou struct。 Veja o seguinte código como exemplo:
Por fim, compila para o seguinte código:
usando o Sistema; usando System.Collections.Generic; usando System.Diagnostics; usando System.Reflection; usando System.Runtime.CompilerServices; usando System.Security; usando System.Security.Permissions; usando System.Text; usando o Microsoft.CodeAnalysis;
[assembleia: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.DisableOptimizations)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [módulo: Código Não Verificável] [módulo: System.Runtime.CompilerServices.RefSafetyRules(11)]
[System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] classe pública PessoaInformação: IEquável<PersonInfo>
{ [CompiladorGerado] [DebuggerBrowsable(DebuggerBrowsableState.Never)] Sequência de leitura somente <FirstName>privada k__BackingField;
[CompiladorGerado] [DebuggerBrowsable(DebuggerBrowsableState.Never)] sequência de leitura <LastName>somente privada k__BackingField;
[CompiladorGerado] Contrato de Igualdade de Tipo virtual protegido { [CompiladorGerado] Obter { return typeof(PersonInfo); } }
String público Primeiro Nome { [CompiladorGerado] Obter { retorno <FirstName>k__BackingField; } [CompiladorGerado] Init { <FirstName>k__BackingField = valor; } }
Sequência pública Sobrenome { [CompiladorGerado] Obter { retorno <LastName>k__BackingField; } [CompiladorGerado] Init { <LastName>k__BackingField = valor; } }
publicaPessoaInfo(stringNomePróprio, SobrenomeCadeiaCadeia) { <FirstName>k__BackingField = Nome; <LastName>k__BackingField = Sobrenome; base.. ctor(); }
[CompiladorGerado] String de override público ToString() { StringBuilder stringBuilder = novo StringBuilder(); stringBuilder.Append("PessoaInfo"); stringBuilder.Append(" { "); if (PrintMembers(stringBuilder)) { stringBuilder.Append(' '); } stringBuilder.Append('}'); return stringBuilder.ToString(); }
[CompiladorGerado] Bool virtual protegido PrintMembers (construtor StringBuilder) { RuntimeHelpers.EnsureSufficientExecutionStack(); construtor. Anexar("Primeiro Nome = "); construtor. Acrescentar((objeto)Nome); construtor. Acrescentar(", Sobrenome = "); construtor. Acrescentar((objeto)Sobrenome); retorno verdadeiro; }
[System.Runtime.CompilerServices.NullableContext(2)] [CompiladorGerado] operador bool estático público !=(PersonInfo esquerda, PersonInfo direita) { retornar! (esquerda == direita); }
[System.Runtime.CompilerServices.NullableContext(2)] [CompiladorGerado] operador público estático ==(PersonInfo esquerda, PersonInfo direita) { return (object)left == direita || ((objeto)left != null && left. Iguais (direita)); }
[CompiladorGerado] override público int GetHashCode() { retorno (EqualityComparer<Type>. Default.GetHashCode(EqualityContract) * -1521134295 + <string>EqualityComparer. Default.GetHashCode(<FirstName>k__BackingField)) * -1521134295 + <string>EqualityComparer. Padrão.GetHashCode(<LastName>k__BackingField); }
[System.Runtime.CompilerServices.NullableContext(2)] [CompiladorGerado] publicamente override bool Equals(object obj) { return Equals(obj como PersonInfo); }
[System.Runtime.CompilerServices.NullableContext(2)] [CompiladorGerado] bool virtual público é igual (PersonInfo out) { return (object)this == outros || ((objeto)outro != nulo && EqualityContract == outro. EqualityContract & <string>EqualityComparer. Padrão. Igual a <FirstName>k__BackingField, outro.<FirstName>k__BackingField) & <string>EqualityComparer. Padrão. Igual(<LastName>k__BackingField), outro.<LastName>k__BackingField)); }
[CompiladorGerado] público, virtual PersonInfo <Clone>$() { return new PersonInfo(this); }
[CompiladorGerado] PessoaInformação protegida (PessoaInformação original) { <FirstName>k__BackingField = original. <FirstName>k__BackingField; <LastName>k__BackingField = original. <LastName>k__BackingField; }
[CompiladorGerado] empty public void Desconstruir (string out FirstName, out string Sobrenome) { Primeiro Nome = isso. NomePró-Nome; Sobrenome = isso. Sobrenome; }
}
Namespace Microsoft.CodeAnalysis
{ [CompiladorGerado] [Embeddado] classe interna, lacrada EmbeddedAttribute : Attribute { }
}
Espaço de nomes System.Runtime.CompilerServices
{ [CompiladorGerado] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AtributoObjetivos.Propriedade | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AtributoAlvos.RetornoValor | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] classe interna selada NullableAttribute : Atributo { byte público de leitura somente NullableFlags;
NullableAttribute(byte P_0) público { byte[] array = novo byte[1]; array[0] = P_0; NullableFlags = array; }
publicamente NullableAttribute(byte[] P_0) { NullableFlags = P_0; } }
[CompiladorGerado] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegar, PermitirMúltiplo = falso, Herdado = falso)] classe internamente lacrada NullableContextAttribute : Attribute { byte público somente leitura Flag;
NullableContextAttribute(byte P_0) público { Bandeira = P_0; } }
[CompiladorGerado] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] classe interna lacrada RefSafetyRulesAtributo : Atributo { versão somente releitura pública int;
Public RefSafetyRulesAttribute(int P_0) { Versão = P_0; } }
} Ele gera automaticamente construtores, reescreve os métodos ToString, GetHashCode, Equals e gera automaticamente alguns métodos.
p1 e p2 são na verdade dois objetos diferentes, mas como o compilador gerou automaticamente o comparador (IEquatable) e reescreveu os métodos Equals e GetHashCode, o resultado era verdadeiro. Chamar o método ToString também é muito intuitivo para gerar o valor registrado. Como mostrado abaixo:
registro
Necessário:required indica que o campo ou atributo que ele aplica deve ser inicializado por todos os construtores ou usando o inicializador de objetos. Qualquer expressão usada para inicializar uma nova instância desse tipo deve inicializar todos os membros necessários. Referência:O login do hiperlink está visível.
Init: Em C# 9 e posteriores, a palavra-chave init define o método do acessor em uma propriedade ou indexador. A biblioteca apenas init atribui valores apenas a atributos ou elementos do indexador durante a construção do objeto. Isso impõe imutabilidade, então, uma vez que um objeto é inicializado, ele não pode mais ser alterado. Referência:O login do hiperlink está visível.
com: Se você precisar replicar uma instância com algumas modificações, pode usar a expressão com para implementar mudanças não destrutivas. com expressão para criar uma nova instância de registro que seja uma cópia de uma instância de registro existente, modificando as propriedades e campos especificados. Referência:O login do hiperlink está visível.
Portanto, o registro pode ser definido da seguinte forma:
Necessário, não é, sem contar que, com realmente açúcar sintaxe, ele vaiChame o método $ gerado automaticamente <Clone>e então modificar o valor do atributo. Como segue:
Código:
Atributo do registro
Às vezes precisamos adicionar algumas características aos atributos, como características de serialização JSON, informações de descrição, etc.
Recursos:
O login do hiperlink está visível.
O login do hiperlink está visível.
|