在本教程中,你将生成一个控制台应用,该应用使用记录和记录结构对每日温度进行建模。
本教程中,您将学习如何:
- 声明位置记录和记录结构。
- 生成小型记录层次结构。
- 使用编译器生成的相等性和格式设置。
- 使用
with表达式进行非破坏性突变。
先决条件
- 最新的 .NET SDK
- Visual Studio Code 编辑器
- C# 开发套件
安装说明
在 Windows 上,可以使用这个 WinGet 配置文件来安装所有必备组件。 如果已安装某些内容,WinGet 将跳过此步骤。
- 下载该文件,然后双击以运行它。
- 阅读许可协议,键入 y,并在系统提示接受时按下 Enter。
- 如果在任务栏中收到闪烁的用户帐户控制(UAC)提示,请允许安装继续。
在其他平台上,需要单独安装其中每个组件。
- 从 .NET SDK 下载页下载建议的安装程序然后双击以运行它。 下载页可检测平台,并推荐平台的最新安装程序。
- 从 Visual Studio Code 主页下载最新的安装程序,然后双击以运行它。 该页还会检测平台,并且链接应该适合你的系统。
- 单击 C# DevKit 扩展页上的“安装”按钮。 这将打开 Visual Studio 代码,并询问是否要安装或启用扩展。 选择“安装”。
创建您的应用和第一条记录
为应用创建文件夹,运行 dotnet new console并打开生成的项目。
添加名为 DailyTemperature.cs的文件,并为温度值添加位置 readonly record struct :
public readonly record struct DailyTemperature(double HighTemp, double LowTemp)
{
public double Mean => (HighTemp + LowTemp) / 2.0;
}
添加名为Program.cs的文件,并创建示例温度数据。
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)
];
此语法提供简洁的数据建模,并提供不可变值语义。
将行为添加到记录结构
在 DailyTemperature.cs 中,记录结构已有计算的 Mean 属性:
public double Mean => (HighTemp + LowTemp) / 2.0;
此处的记录结构非常有效,因为每个值都是小而独立的。
为度日计算构建记录类型
注释
取暖度日 和 冷却度日 测量日均温度与基本温度(通常为 65°F/18°C)的差值。 当平均数低于基准时,取暖度日累积在冷日,而当平均数高于基准时,冷度日累积在暖日。 这些计算有助于估计供热或冷却建筑物的能耗,使它们对公用事业公司、建筑经理和气候分析很有用。
创建一个名为DegreeDays.cs的文件,其中包含用于加热和冷却度日计算的层次结构。
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);
}
现在,根据 Program.cs 中的 Main 方法计算总计:
var heatingDegreeDays = new HeatingDegreeDays(65, data);
Console.WriteLine(heatingDegreeDays);
var coolingDegreeDays = new CoolingDegreeDays(65, data);
Console.WriteLine(coolingDegreeDays);
在迭代过程中,生成的 ToString 输出可用于快速诊断。
重写 PrintMembers 以自定义输出
当默认输出包含过多干扰时,在基本记录中重写 PrintMembers :
protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"BaseTemperature = {BaseTemperature}");
return true;
}
重写会使输出侧重于所需的信息。
与表达式配合使用来应对非破坏性变化
用于 with 创建修改的副本,而不改变原始记录:
// Growing degree days measure warming to determine plant growing rates
var growingDegreeDays = coolingDegreeDays with { BaseTemperature = 41 };
Console.WriteLine(growingDegreeDays);
扩展该想法,从输入数据的切片计算滚动总计:
// 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);
}
在保留原始值时需要转换时,此方法非常有用。