在這個教學中,你會建立一個主控台應用程式,透過記錄和記錄結構來模擬每日溫度。
在這個教學中,你會學到如何:
- 宣告位置記錄和記錄結構。
- 建立一個小型的記錄階層。
- 採用編譯器生成的相等性判斷和格式化。
- 使用非破壞性突變的
with表達式。
Prerequisites
- 最新的 .NET SDK
- Visual Studio Code 編輯器
- C# 開發套件
安裝指示
在 Windows 上,這個 WinGet 設定檔 用來安裝所有前置條件。 如果您已安裝某些專案,WinGet 將會略過此步驟。
- 下載檔案,然後按兩下以執行它。
- 閱讀許可協議,輸入 y,然後在系統提示接受時選取 [輸入]。
- 如果您在任務欄中收到閃爍的用戶帳戶控制 (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);
}
現在用你的Main方法計算總和:Program.cs
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);
}
這種方法在需要轉換並保留原始值時非常有用。