HOWTO · Csharp
在 C# 中將 decimal 轉換為 int
說明在 C# 中將 decimal 轉換為 int 時,如何選擇截斷、四捨五入或定向捨入規則,並處理超出 Int32 範圍的值。
本頁內容
如果要捨棄小數部分,請使用 (int)value;如果要捨入到最接近的整數,請使用 Convert.ToInt32(value);如果規則是定向捨入或具有特定的中點處理方式,請使用 Math 方法。下面的精簡範例以正數比較這些選項。
using System;
class Program
{
static void Main()
{
decimal value = 12.9m;
Console.WriteLine("cast: " + (int)value);
Console.WriteLine("nearest: " + Convert.ToInt32(12.5m) + ", " + Convert.ToInt32(13.5m));
Console.WriteLine("floor: " + Math.Floor(value));
Console.WriteLine("ceiling: " + Math.Ceiling(value));
Console.WriteLine("away: " + Math.Round(2.5m, MidpointRounding.AwayFromZero));
}
}
cast: 12
nearest: 12, 14
floor: 12
ceiling: 13
away: 3
轉換策略是業務規則,而不是格式設定細節。如果小數部分仍然有意義,例如金額或測量值,請將值保留為 decimal。最後轉換為 int 時,也必須處理不符合 Int32 範圍的值。
將 decimal 朝零截斷
如果要截斷,明確的型別轉換 (int)value 是最清楚的選擇。decimal 常值需要 m 後綴;沒有後綴的 12.9 這類常值會是 double。將 decimal 轉換為整數型別時會朝零捨入:(int)12.9m 是 12,而 (int)-12.9m 是 -12。這既不是 floor,也不是 ceiling。C# 數值轉換參考說明了朝零的行為和超出範圍時的失敗情況。
捨入到最接近的整數
Convert.ToInt32(decimal) 會捨入到最接近的 32 位元帶正負號整數,而不是截斷。當小數部分恰好是 .5 時,它會使用中點向偶數捨入:Convert.ToInt32(12.5m) 是 12,而 Convert.ToInt32(13.5m) 是 14。這適合需要取最接近完整單位的測量值,但如果每個中點都必須遠離零捨入,就不適合使用這項規則。
Convert.ToInt32 的 decimal 多載文件說明,超出 int 範圍的值會產生 OverflowException。這個方法不會讓超大的 decimal 自動變得安全。
選擇明確的捨入規則
請先對 decimal 套用 Math 方法,再轉換其整數結果。Math.Floor 會朝負無限大移動,因此 Math.Floor(-12.9m) 是 -13m;Math.Ceiling 則會朝正無限大移動。因此兩者都與 (int)-12.9m 的 -12 不同。
如果要以明確的中點規則進行最接近值捨入,請使用 Math.Round(value, MidpointRounding.AwayFromZero)。它會將 2.5m 變成 3m,並將 -2.5m 變成 -3m。預設的 Math.Round(decimal) 則使用中點向偶數捨入。Math.Truncate 是另一種清楚取得朝零整數化 decimal 的方式,之後再將其轉換為 int。
不要在捨入前先進行型別轉換:(int)value 已經捨棄小數部分,之後呼叫 Math.Round 也無法恢復原本想採用的規則。請先捨入、檢查結果,然後再進行型別轉換。
處理超出 int 範圍的值
int 是由 int.MinValue 到 int.MaxValue 的 32 位元帶正負號整數;Int32 是相應的 framework 型別。decimal 可以表示超出這些邊界的值。當結果超出該範圍時,decimal 到 int 的轉換會產生 OverflowException;它不會將值限制到某個端點。
如果輸入可能超出範圍,請在轉換前驗證值,或在應用程式邊界捕捉 OverflowException。checked 轉換可以明確表達意圖,也有助於測試範圍契約,但它不是偵測 decimal 到 int 轉換溢位的機制。如果接收端契約允許,請保留 decimal 或改用更寬的整數型別,而不要默默將值強制塞入 int。
選擇符合規則的轉換
| 目標結果 | 使用方式 | 重要行為 |
|---|---|---|
| 捨棄小數部分 | (int)value |
朝零截斷。 |
最接近的 int |
Convert.ToInt32(value) |
中點向偶數捨入。 |
| 始終向下或向上 | Math.Floor 或 Math.Ceiling 後再轉換 |
對負數而言不同於截斷。 |
| 自訂中點行為 | 使用 MidpointRounding 的 Math.Round 後再轉換 |
明確寫出中點處理規則。 |
一般截斷請選擇明確的型別轉換。只有在應用程式需要該捨入策略時,才選擇 Convert.ToInt32 或 Math 方法,並在 int 邊界處理 OverflowException。