Utilizar tipos de registo

Dica

Novo no desenvolvimento de software? Começa primeiro pelos tutoriais para começar . Ficas confortável com classes, métodos e loops ali.

Experiente noutra língua? Este tutorial foca-se nas funcionalidades de registo em C# que usas todos os dias: igualdade de valores, sintaxe posicional e with expressões.

Neste tutorial, constróis uma aplicação de consola que modela as temperaturas diárias usando registos e estruturas de registo.

Neste tutorial, aprenderás como:

  • Declara registos posicionais e estruturas de registo.
  • Constrói uma pequena hierarquia de registros.
  • Use igualdade e formatação geradas pelo compilador.
  • Use expressões with para uma mutação não destrutiva.

Pré-requisitos

Instruções de instalação

No Windows, utilize este ficheiro 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 surgir um aviso de Controle de Conta de Utilizador (UAC) intermitente na barra de tarefas, permita que a instalação prossiga.

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 deteta sua plataforma e recomenda o instalador mais recente para sua plataforma.
  2. Descarregue o instalador mais recente na página inicial Visual Studio Code e clique duas vezes para o executar. Essa página também deteta a sua plataforma e o link deve estar correto para o seu sistema.
  3. Clique no botão "Instalar" na página de extensão C# DevKit. Isso abre o código do Visual Studio e pergunta se queres instalar ou ativar a extensão. Selecione "instalar".

Crie a aplicação e o seu primeiro registo

Cria uma pasta para a tua aplicação, executa dotnet new console, e abre o projeto gerado.

Adicione um ficheiro chamado DailyTemperature.cs, e adicione um posicional readonly record struct para os valores de temperatura:

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

Adicione um ficheiro chamado Program.cs, e crie dados de temperatura de amostra:

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) 
];

Esta sintaxe dá-lhe uma modelação de dados concisa com semântica de valores imutável.

Adicionar comportamento à estrutura de registo

Em DailyTemperature.cs, a estrutura de registo já possui uma propriedade computada Mean :

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

Uma estrutura de registo funciona bem aqui porque cada valor é pequeno e autónomo.

Criar tipos de registo para cálculos de grau-dia

Observação

Os graus-dia de aquecimento e graus-dia de arrefecimento medem quanto a temperatura média diária se desvia de uma temperatura base (tipicamente 65°F/18°C). Os graus-dia de aquecimento acumulam-se em dias frios quando a média está abaixo da base, enquanto os graus-dia de arrefecimento acumulam-se em dias quentes em que a média está acima da base. Estes cálculos ajudam a estimar o consumo de energia para edifícios de aquecimento ou arrefecimento, tornando-os úteis para empresas de serviços públicos, gestores de edifícios e análises climáticas.

Crie um ficheiro nomeado DegreeDays.cs com uma hierarquia para cálculos de grau-dia de aquecimento e arrefecimento:

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 a partir do seu Main método 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 rápidos diagnósticos enquanto realiza iterações.

Substituir PrintMembers para configurar a saída

Quando a saída padrão inclui demasiado ruído, substitua PrintMembers no registo base:

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

A sobreposição mantém o resultado focado na informação necessária.

Uso de expressões para mutações não destrutivas

Use with para criar cópias modificadas sem alterar o registo 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 rolativos a partir de fatias dos teus 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);
}

Esta abordagem é útil quando precisas de transformações enquanto preservas os valores originais.

Passos seguintes