首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

深入探討 Nullable 型別轉換:從 Convert 失敗到擴充方法完美解決方案

     編輯:關於C語言

本文探討可為 null 的實值型別(Nullable<T>)的型別轉換難題:如何將任意型別物件轉換為對應的可為 null 型別。這源自團隊成員遇到的實際問題,經整理後分享給大家。

四種常見型別轉換方式

  1. 強制轉換運算子:int intValue = (int)doubleValue;
  2. Convert 靜態類別:int val = Convert.ToInt32("123"); 或 Convert.ChangeType(obj, typeof(int))
  3. TypeConverter 衍生類別:如 DateTimeConverter、BooleanConverter
  4. Parse/TryParse 靜態方法:DateTime.Parse("2024-01-01")

Nullable 型別轉換的陷阱

Convert.ChangeType 無法直接轉換為 Nullable<T>:

string literalValue = "123";
try
{
    int? intValue = (int?)Convert.ChangeType(literalValue, typeof(int?));
}
catch (InvalidCastException ex)
{
    Console.WriteLine(ex.Message);
    // 輸出:Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int32...]]'
}

即使來源已是 int 也會失敗:

int intValue1 = 123;
int? intValue = (int?)Convert.ChangeType(intValue1, typeof(int?)); // 同樣拋出例外

但實際上 int 可隱式/顯式轉為 int?:

int? v1 = 123;      // 隱式
int? v2 = (int?)123; // 顯式

解決方案:擴充方法實作 Nullable 轉換

第一版:針對 Nullable<T> 專用

public static class ConvertionExtensions
{
    public static T? ConvertTo(this IConvertible convertibleValue) where T : struct
    {
        if (convertibleValue == null) return null;
        return (T?)Convert.ChangeType(convertibleValue, typeof(T));
    }
}

// 使用範例
int? i = "123".ConvertTo();
double? d = "123".ConvertTo();
DateTime? dt = "1981-08-24".ConvertTo();

完善版:支援任意目標型別(含 Nullable 與非 Nullable)

public static T ConvertTo(this IConvertible convertibleValue)
{
    if (convertibleValue == null) return default(T);
    
    if (!typeof(T).IsGenericType)
    {
        return (T)Convert.ChangeType(convertibleValue, typeof(T));
    }
    else
    {
        Type genericDef = typeof(T).GetGenericTypeDefinition();
        if (genericDef == typeof(Nullable<>))
        {
            Type underlying = Nullable.GetUnderlyingType(typeof(T));
            return (T)Convert.ChangeType(convertibleValue, underlying);
        }
    }
    throw new InvalidCastException($"Invalid cast from '{convertibleValue.GetType().FullName}' to '{typeof(T).FullName}'.");
}

// 統一介面調用
int i1 = "123".ConvertTo();
int? i2 = "123".ConvertTo();
DateTime dt1 = "1981-08-24".ConvertTo();
DateTime? dt2 = "1981-08-24".ConvertTo();

關鍵技術點解析

  • typeof(T).IsGenericType:判斷是否為泛型型別
  • GetGenericTypeDefinition():取得泛型定義(如 Nullable<>)
  • Nullable.GetUnderlyingType():取得 Nullable 包裝的實際型別(如 Int32)

替代方案:NullableConverter

.NET 內建 NullableConverter 專門處理 Nullable 型別轉換:

string literalValue = "1981-08-24";
NullableConverter converter = new NullableConverter(typeof(DateTime?));
DateTime? dateTimeValue = (DateTime?)converter.ConvertFromString(literalValue);

適用於資料繫結、屬性網格等設計時期場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved