VB.NET 數據類型轉換 筆記(精進篇)
VB.NET 程式常會遇到資料型別不一致的情況。例如表單輸入是文字,但計算需要數字;資料庫欄位是日期,但畫面需要格式化文字;二進位封包是位元組陣列,但程式需要還原成整數。
型別轉換的重點不只是「能不能轉」,而是轉換後是否安全、是否會遺失資料、失敗時是否能保留流程。這篇整理常見轉換方式,包含 CType、DirectCast、TryCast、Parse、TryParse、ParseExact、BitConverter、裝箱拆箱與自訂轉換。
型別轉換的核心觀念
先判斷轉換風險
型別轉換可先分成兩個方向:一種是比較安全的擴大型轉換,另一種是可能有風險的縮小型轉換。
- 擴大型轉換:目標型別容量較大,來源值通常能完整放入,例如
Integer轉成Long。 - 縮小型轉換:目標型別容量較小,或無法完整保存小數與精度,例如
Decimal轉成Integer。 - 外部資料轉換:來源可能格式錯誤,例如表單輸入、CSV、API、檔案內容,通常需要使用安全判斷。
轉換前建議檢查三件事:
- 範圍:目標型別是否足以容納來源值。
- 精度:小數位、有效數字或日期格式是否會改變。
- 失敗處理:格式錯誤、溢位或型別不相容時,是否需要避免程式中斷。
| 判斷面向 | 風險較低 | 風險較高 |
|---|---|---|
| 數值範圍 | 目標型別範圍更大。 | 目標型別範圍更小,可能溢位。 |
| 資料精度 | 位數與小數可完整保留。 | 可能發生捨入、截斷或格式改變。 |
| 資料來源 | 程式內部固定資料。 | 表單輸入、檔案、API、使用者貼上內容。 |
| 失敗處理 | 失敗機率低,可直接轉換。 | 失敗機率高,應優先使用 TryParse 或 TryCast。 |
執行環境與範例形式
Windows Forms 物件配置
以下範例以 Windows Forms 為主。每個場景都保留完整範例程式碼,方便直接建立測試。
Button1:執行轉換範例。TextBox1:輸入要轉換的文字資料。Label1:顯示單一或多行轉換結果。ListBox1:顯示多筆輸出,例如位元組陣列內容。
內建數值型別轉換
場景一:擴大型轉換 Integer → Long
當來源型別可完整放入目標型別時,通常屬於擴大型轉換。例如 Integer 是 32 位元整數,Long 是 64 位元整數,Long 可容納更大的整數範圍。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim monthlyOrderCount As Integer = 48215
Dim annualOrderCount As Long = monthlyOrderCount
Label1.Text = "原始型別:" & monthlyOrderCount.GetType().Name & vbCrLf &
"轉換後型別:" & annualOrderCount.GetType().Name & vbCrLf &
"轉換後值:" & annualOrderCount.ToString("N0")
End Sub
End Class
邏輯解析
Integer對應執行階段型別Int32。Long對應執行階段型別Int64。- 較小範圍的整數放入較大範圍的整數,資料不會遺失。
- 這類轉換通常可直接指定,不需要額外寫
CType。
場景二:縮小型轉換 Decimal → Integer
Decimal 轉成 Integer 時,小數部分無法原樣保留,因此屬於縮小型轉換。這類轉換應明確寫出來,避免看不出資料可能被改變。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim packageWeight As Decimal = 13.75D
Dim roundedWeight As Integer = CType(packageWeight, Integer)
Label1.Text = "原始 Decimal:" & packageWeight.ToString() & vbCrLf &
"轉換後 Integer:" & roundedWeight.ToString()
End Sub
End Class
邏輯解析
CType(packageWeight, Integer)明確表示此處發生型別轉換。Decimal可保存小數,Integer只能保存整數。- 轉成整數後,小數精度不會保留。
- 涉及重量、金額、測量值時,應特別留意四捨五入或精度遺失是否符合需求。
縮小型轉換的常見風險
縮小型轉換不只可能改變小數,也可能因來源值超過目標型別範圍而產生例外。金額、小數、統計值、外部匯入資料都應明確處理轉換規則。
參考型別轉換:DirectCast 與 TryCast
場景三:已確定實際型別時使用 DirectCast
DirectCast 適合用在實際型別已經確定的情境。若實際物件確實是目標型別,就能轉換成功;若不是,會直接產生 InvalidCastException。
範例程式碼
Public Class NotificationChannel
Public Property ChannelName As String
End Class
Public Class SmsChannel
Inherits NotificationChannel
Public Property PhoneNumber As String
End Class
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim baseChannel As NotificationChannel = New SmsChannel With {
.ChannelName = "系統簡訊",
.PhoneNumber = "0900-123-456"
}
Dim sms As SmsChannel = DirectCast(baseChannel, SmsChannel)
Label1.Text = "通道名稱:" & sms.ChannelName & vbCrLf &
"接收號碼:" & sms.PhoneNumber
End Sub
End Class
邏輯解析
baseChannel的宣告型別是NotificationChannel。- 實際建立的物件是
SmsChannel,因此可轉回SmsChannel。 - 轉換成功後,可讀取
SmsChannel才有的PhoneNumber屬性。 - 若實際物件不是
SmsChannel,DirectCast會產生例外。
場景四:不確定型別時使用 TryCast
TryCast 適合用在成功與否不確定的參考型別轉換。轉換失敗時不會丟出例外,而是回傳 Nothing。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim rawControl As Object = Label1
Dim inputBox As TextBox = TryCast(rawControl, TextBox)
If inputBox Is Nothing Then
Label1.Text = "TryCast 失敗:來源物件不是 TextBox。"
Else
Label1.Text = "TextBox 內容:" & inputBox.Text
End If
End Sub
End Class
邏輯解析
rawControl實際指向的是Label1。TryCast(rawControl, TextBox)嘗試把它轉成TextBox。- 因為實際型別不符合,所以
inputBox會是Nothing。 TryCast只能用於參考型別,不能用來轉換Integer、Decimal這類值型別。
字串與數值的轉換
場景五:使用 Integer.Parse 解析固定格式資料
Parse 適合資料格式已確定的情況。例如內部設定、固定格式檔案、已驗證過的欄位。若文字格式錯誤,Parse 會直接產生例外。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = "256"
Dim quantityText As String = TextBox1.Text.Trim()
Dim quantity As Integer = Integer.Parse(quantityText)
Label1.Text = "解析成功,數值 = " & quantity.ToString()
End Sub
End Class
邏輯解析
Integer.Parse會把文字轉成整數。- 本例的
TextBox1.Text是固定填入的256,格式可預期。 - 若輸入變成
7A5,Parse會產生格式錯誤例外。 - 自由輸入欄位通常不建議直接使用
Parse。
場景六:使用 Integer.TryParse 處理表單輸入
TryParse 適合處理不穩定來源,例如表單輸入、匯入檔、貼上內容與外部資料。轉換成功時回傳 True,失敗時回傳 False,流程不會被例外中斷。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim stockText As String = TextBox1.Text.Trim()
Dim stockValue As Integer
If Integer.TryParse(stockText, stockValue) Then
Label1.Text = "庫存數量:" & stockValue.ToString("N0")
Else
Label1.Text = "輸入無法轉成整數,請檢查是否含有非數字字元。"
End If
End Sub
End Class
邏輯解析
Integer.TryParse(stockText, stockValue)會嘗試把文字轉成整數。- 成功時回傳
True,並把結果放入stockValue。 - 失敗時回傳
False,程式可顯示錯誤訊息,而不是直接中斷。 - 表單輸入與外部資料通常優先使用
TryParse。
Parse 與 TryParse 的差異
Parse 適合資料應該正確的情境;TryParse 適合資料可能錯誤的情境。資料來源越靠近外部輸入,越應優先使用 TryParse。
日期時間轉換
場景七:使用 Date.TryParseExact 解析固定日期格式
日期文字若來自報表、交換檔或跨系統傳輸,不應完全依賴系統地區設定自動判讀。固定格式搭配 TryParseExact 可同時保留格式嚴謹與失敗防護。
範例程式碼
Imports System.Globalization
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sourceText As String = TextBox1.Text.Trim()
Dim confirmedDate As Date
If Date.TryParseExact(sourceText,
"yyyy-MM-dd HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
confirmedDate) Then
Label1.Text = "解析成功:" & confirmedDate.ToString("yyyy/MM/dd HH:mm:ss")
Else
Label1.Text = "日期格式不正確,請輸入 yyyy-MM-dd HH:mm:ss"
End If
End Sub
End Class
邏輯解析
TryParseExact要求來源文字符合指定格式。yyyy-MM-dd HH:mm:ss代表來源必須像2026-06-15 14:20:30。CultureInfo.InvariantCulture可降低不同地區設定造成的解析差異。- 解析失敗時不會丟出例外,而是進入
Else顯示提示。
位元組陣列與基本型別轉換
場景八:使用 BitConverter 將 Int32 轉成 Byte()
二進位檔案、設備通訊、封包組合與序列化過程,常需要把數值轉成位元組陣列。BitConverter.GetBytes 可將基本型別轉成 Byte()。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sensorValue As Integer = 1024
Dim packetBytes As Byte() = BitConverter.GetBytes(sensorValue)
ListBox1.Items.Clear()
ListBox1.Items.Add("原始整數:" & sensorValue.ToString())
ListBox1.Items.Add("位元組序列:" & BitConverter.ToString(packetBytes))
ListBox1.Items.Add("陣列長度:" & packetBytes.Length.ToString())
ListBox1.Items.Add("系統是否為小端序:" & BitConverter.IsLittleEndian.ToString())
End Sub
End Class
邏輯解析
Integer是 32 位元整數,因此轉成Byte()後長度為 4。BitConverter.ToString(packetBytes)可把位元組陣列轉成易讀的十六進位字串。- 輸出順序與系統大小端序有關。
- 與外部設備或封包規格交換資料時,需確認對方使用的位元組順序。
場景九:將 Byte() 還原回 Int32
接收封包或檔案資料後,若位元組排列與格式正確,可透過 BitConverter.ToInt32 還原整數。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim incomingBytes As Byte() = {44, 1, 0, 0}
Dim restoredNumber As Integer = BitConverter.ToInt32(incomingBytes, 0)
Label1.Text = "來源位元組:" & BitConverter.ToString(incomingBytes) & vbCrLf &
"還原數值:" & restoredNumber.ToString()
End Sub
End Class
邏輯解析
ToInt32(incomingBytes, 0)表示從索引 0 開始讀取 4 個位元組。2C-01-00-00在小端序環境中會還原為 300。- 若起始位置錯誤或位元組長度不足,還原結果會錯誤或產生例外。
- 處理封包時,位移位置通常需依照規格文件管理。
裝箱與拆箱
場景十:值型別存入 Object,再還原成原型別
值型別放入 Object 時會發生裝箱。之後若要取回原本的值型別,就會發生拆箱。此類情境常見於舊版 API、通用集合或需要以 Object 暫存資料的流程。
範例程式碼
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim originalScore As Integer = 88
Dim boxedValue As Object = originalScore
Dim restoredScore As Integer = CType(boxedValue, Integer)
Label1.Text = "原始值:" & originalScore.ToString() & vbCrLf &
"裝箱後型別:" & boxedValue.GetType().Name & vbCrLf &
"拆箱後值:" & restoredScore.ToString()
End Sub
End Class
邏輯解析
Integer是值型別,放入Object時會被裝箱。boxedValue.GetType().Name仍顯示實際內容是Int32。CType(boxedValue, Integer)會把裝箱後的值還原成Integer。- 拆箱時型別必須正確,否則可能產生轉換例外。
自訂型別轉換
場景十一:為自訂類別建立 CType 轉換邏輯
若某個類別本身代表明確的數值概念,可把轉換規則放進類別內部。例如儲存空間配額可由整數建立,也可轉回整數顯示。
範例程式碼
Public Class StorageQuota
Public Property CapacityInGB As Integer
Public Shared Widening Operator CType(value As Integer) As StorageQuota
Return New StorageQuota With {.CapacityInGB = value}
End Operator
Public Shared Narrowing Operator CType(quota As StorageQuota) As Integer
Return quota.CapacityInGB
End Operator
End Class
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim quota As StorageQuota = 250
Dim rawValue As Integer = CType(quota, Integer)
Label1.Text = "配額物件:" & quota.CapacityInGB.ToString() & " GB" & vbCrLf &
"轉回整數:" & rawValue.ToString() & " GB"
End Sub
End Class
邏輯解析
Widening Operator CType定義由Integer建立StorageQuota的規則。Narrowing Operator CType定義由StorageQuota轉回Integer的規則。Dim quota As StorageQuota = 250可成立,是因為類別定義了整數到物件的轉換。- 自訂轉換可提升語意,但規則必須直觀,否則會降低程式可讀性。
實務選用整理
| 情境 | 建議方法 | 說明 |
|---|---|---|
| 安全擴大型轉換 | 直接指定 |
資料範圍可完整保留時,通常不需額外語法。 |
| 縮小型轉換 | CType |
明確表達可能存在精度變化或例外風險。 |
| 已知參考型別 | DirectCast |
實際型別確定時可使用;錯誤時會產生例外。 |
| 不確定參考型別 | TryCast |
失敗時回傳 Nothing,可避免流程中斷。 |
| 固定合法字串 | Parse |
適合可控來源,不適合自由輸入。 |
| 表單或外部輸入 | TryParse |
失敗時可顯示提示,流程仍能繼續。 |
| 固定日期格式 | TryParseExact |
可同時控制格式並避免例外中斷。 |
| 二進位資料 | BitConverter |
適合基本型別與位元組陣列互轉,但需注意大小端序。 |
- 型別轉換前應先判斷範圍、精度與失敗風險。
- 擴大型轉換通常較安全;縮小型轉換應明確寫出轉換語法。
- 表單輸入、檔案、API 等外部資料,通常優先使用
TryParse。 - 參考型別已確定時可用
DirectCast;不確定時可用TryCast。 - 日期文字若格式固定,使用
TryParseExact比自動解析更穩定。 BitConverter適合處理封包與二進位資料,但需留意位元組順序。- 自訂轉換能提升語意,但規則必須直觀,避免造成隱藏邏輯。