Usar tipos de registro

Dica

Novo no desenvolvimento de software? Comece primeiro com os tutoriais de Introdução . Você se sente confortável com classes, métodos e loops neste contexto.

Experimentou em outro idioma? Este tutorial se concentra nos recursos de registro em C# que você usa todos os dias: igualdade de valor, sintaxe posicional e with expressões.

Neste tutorial, você vai criar um aplicativo de console que modela temperaturas diárias usando registros e estruturas de registro.

Neste tutorial, você aprenderá como:

  • Declare registros posicionais e estruturas de registro.
  • Crie uma hierarquia de registro pequena.
  • Use a igualdade e a formatação geradas pelo compilador.
  • Use expressões with para mutação não destrutiva.

Pré-requisitos

Instruções de instalação

No Windows, use este arquivo de configuração WinGet para instalar todos os pré-requisitos. Se você já tiver algo instalado, o WinGet ignorará essa etapa.

  1. Baixe o arquivo e clique duas vezes para executá-lo.
  2. Leia o contrato de licença, digite ye selecione Enter quando solicitado a aceitar.
  3. Se você receber um prompt de UAC (Controle de Conta de Usuário) piscando na barra de tarefas, permita que a instalação continue.

Em outras plataformas, você precisa instalar cada um desses componentes separadamente.

  1. Baixe o instalador recomendado na página de download do .NET SDK e clique duas vezes para executá-lo. A página de download detecta sua plataforma e recomenda o instalador mais recente para sua plataforma.
  2. Baixe o instalador mais recente da home page Visual Studio Code e clique duas vezes para executá-lo. Essa página também detecta sua plataforma e o link deve estar correto para o sistema.
  3. Clique no botão "Instalar" na página de extensão do DevKit em C#. Isso abre o código do Visual Studio e pergunta se você deseja instalar ou habilitar a extensão. Selecione "instalar".

Crie seu aplicativo e seu primeiro cadastro

Crie uma pasta para seu aplicativo, execute dotnet new consolee abra o projeto gerado.

Adicione um arquivo chamado DailyTemperature.cse adicione um posicionamento readonly record struct para valores de temperatura:

public readonly record struct DailyTemperature(double HighTemp, double LowTemp)
{
    public double Mean => (HighTemp + LowTemp) / 2.0;
}

Adicione um arquivo chamado Program.cse crie dados de temperatura de exemplo:

private static DailyTemperature[] data = [
    new DailyTemperature(HighTemp: 57, LowTemp: 30), 
    new DailyTemperature(60, 35),
    new DailyTemperature(63, 33),
    new DailyTemperature(68, 29),
    new DailyTemperature(72, 47),
    new DailyTemperature(75, 55),
    new DailyTemperature(77, 55),
    new DailyTemperature(72, 58),
    new DailyTemperature(70, 47),
    new DailyTemperature(77, 59),
    new DailyTemperature(85, 65),
    new DailyTemperature(87, 65),
    new DailyTemperature(85, 72),
    new DailyTemperature(83, 68),
    new DailyTemperature(77, 65),
    new DailyTemperature(72, 58),
    new DailyTemperature(77, 55),
    new DailyTemperature(76, 53),
    new DailyTemperature(80, 60),
    new DailyTemperature(85, 66) 
];

Essa sintaxe fornece modelagem de dados concisa com semântica de valor imutável.

Adicionar comportamento à estrutura de registro

Em DailyTemperature.cs, a estrutura de registro já tem uma propriedade computada Mean:

public double Mean => (HighTemp + LowTemp) / 2.0;

Um struct de registro funciona bem aqui porque cada valor é pequeno e autocontido.

Criar tipos de registro para cálculos de grau por dia

Note

Os dias de aquecimento e os dias de resfriamento medem o quanto a temperatura média diária se desvia de uma temperatura base (normalmente 65°F/18°C). Graus por dia de aquecimento se acumulam em dias frios quando a média está abaixo da base, enquanto graus por dia de resfriamento se acumulam em dias quentes quando a média está acima da base. Esses cálculos ajudam a estimar o consumo de energia para aquecimento ou resfriamento de edifícios, tornando-os úteis para empresas de serviços públicos, gerentes de construção e análise climática.

Crie um arquivo nomeado DegreeDays.cs com uma hierarquia para cálculos de dia de aquecimento e resfriamento:

public abstract record DegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords);

public sealed record HeatingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
    : DegreeDays(BaseTemperature, TempRecords)
{
    public double DegreeDays => TempRecords.Where(s => s.Mean < BaseTemperature).Sum(s => BaseTemperature - s.Mean);
}

public sealed record CoolingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
    : DegreeDays(BaseTemperature, TempRecords)
{
    public double DegreeDays => TempRecords.Where(s => s.Mean > BaseTemperature).Sum(s => s.Mean - BaseTemperature);
}

Agora calcule os totais do método Main em Program.cs:

var heatingDegreeDays = new HeatingDegreeDays(65, data);
Console.WriteLine(heatingDegreeDays);

var coolingDegreeDays = new CoolingDegreeDays(65, data);
Console.WriteLine(coolingDegreeDays);

A saída gerada ToString é útil para diagnósticos rápidos enquanto você faz iterações.

Substituir PrintMembers para personalizar a saída

Quando a saída padrão incluir muito ruído, substitua PrintMembers no registro base:

protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
    stringBuilder.Append($"BaseTemperature = {BaseTemperature}");
    return true;
}

A substituição mantém a saída focada nas informações necessárias.

Usar expressões "with" para mutação não destrutiva

Use with para criar cópias modificadas sem alterar o registro original:

// Growing degree days measure warming to determine plant growing rates
var growingDegreeDays = coolingDegreeDays with { BaseTemperature = 41 };
Console.WriteLine(growingDegreeDays);

Estenda essa ideia para calcular totais cumulativos a partir de fatias dos seus dados de entrada.

// showing moving accumulation of 5 days using range syntax
List<CoolingDegreeDays> movingAccumulation = new();
int rangeSize = (data.Length > 5) ? 5 : data.Length;
for (int start = 0; start < data.Length - rangeSize; start++)
{
    var fiveDayTotal = growingDegreeDays with { TempRecords = data[start..(start + rangeSize)] };
    movingAccumulation.Add(fiveDayTotal);
}
Console.WriteLine();
Console.WriteLine("Total degree days in the last five days");
foreach(var item in movingAccumulation)
{
    Console.WriteLine(item);
}

Essa abordagem é útil quando você precisa de transformações enquanto preserva valores originais.

Próximas Etapas