這個建議做法推薦我們多使用 var(隱含型別的區域變數),讓 compiler 自行推斷實際的類型。
當編譯器看到 var 關鍵字時會參考 = 右側的運算式,背後宣告這個區域變數的型別,可以省掉我們自行判斷宣告型別的流程。
第二個好處是能避免變數被錯誤宣告為不正確的型別。常見的問題就是 IEnumerable<T> 和 IQueryable<T> 轉換錯誤導致的性能問題。
當我們使用 EFCore 搭配 LINQ 來存取資料庫數據時,會使用到LINQ to Objects 與 LINQ to SQL 來篩選或排序我們想要的資料。
由於 IEnumerable<T> 和 IQueryable<T> 在使用上相似,因此在進行 LINQ to SQL 操作時,
有時會強制將結果變數宣告為 IEnumerable<T>。然而,這種強制轉換會使程式無法享受 IQueryable<T> 所帶來的好處。
使用 var 關鍵字讓編譯器自動推斷變數類型,則能避免此問題並充分利用 IQueryable<T> 的特性。
使用 var 搭配有可讀性的變數名稱,能幫助開發者更容易理解變數的用途。例如,當我們看到 Dictionary<int, Queue<string>> 這樣的類型時,
可能需要花些時間思考它的用途。然而,這種明確宣告的類型並不一定能幫助理解。因此,不如直接使用 var 並將變數名稱改為更具意義的名稱,
例如 jobsQueuedByRegion,這樣反而能讓我們更快地理解變數的目的和功能。
有可讀性的變數名稱
這個例子中我們可以很輕易的從右側的運算式推測出 foo 變數的類型為 MyType。
var foo = new MyType();
從這個 Factory 也能夠推測出這個 thing 變數應該是跟 Account 類型有相關。
var thing = AccountFactory.CreateSavingAccount();
但是也有可能沒辦法從右側的運算式推測出具體的類型,這個例子中 result 這個名稱沒辦法從語意推測出類型或涵義,
並且右側的 DoSomeWork 方法回傳類型也很不明確。
var result = someObject.DoSomeWork(anotherParameter);
所以可以從 result 這個變數名稱下手,至少讓開發者推測這個變數應該和 Product 類型有關。
var HighestSellingProduct = someObject.DoSomeWork(anotherParameter)
這也產生另一種可讀性的問題,可能第一個工程師推斷這個變數是 Product 類型,但第二個工程師可能覺得是另一個衍生類型 HighestSellingProduct。
假設我們想要的類型為 Product 但編譯器推斷成 HighestSellingProduct 那麼這種情況就不應該使用使用 var,
數值轉型問題
在宣告數值相關的變數時要額外小心,var 推測可能會導致精度的喪失。
在下方的例子中,GetMagicNumber 方法回傳的類型為 decimal,同時宣告的變數 f 類型也會為 decimal,最後在計算 total 時也會知道類型為 decimal,
另一個常見的錯誤是計算 total1 時,右側沒有指定類型導致結果精度丟失。
void Main()
{
var f = GetMagicNumber();
var total = 100 * f / 6;
Console.WriteLine($"Declared Type: {total.GetType().Name}, Value: {total}");
decimal total1 = 100 * 10 / 6;
Console.WriteLine($"Declared Type: {total1.GetType().Name}, Value: {total1}");
}
public decimal GetMagicNumber()
{
return 10;
}
Declared Type: Decimal, Value: 166.66666666666666666666666667
Declared Type: Decimal, Value: 166
Summary
- 除非開發者必須看到宣告型別才能理解程式,否則就使用 var 宣告區域變數。
- 明確宣告數值類別的型別(int、float、double...),不要使用 var 宣告區域變數。
- 其他情況就使用 var 搭配有可讀性的變數名稱。