三、将基于Nullable<T>的类型转换实现在扩展方法中
从上面的介绍我们可以得出这样的结论:如果类型T1和T2能够相互兼容,我们可以借助Convert将T1类型对象转换成T2类型,然后通过显式类型转换进一步转换成Nullable<T2>。我们可以通过这两个步骤实现针对于Nullable<T>类型的转换。为了操作方便,我将此转换逻辑写在针对IConvertible接口的扩展方法中:
- public static class ConvertionExtensions
- {
- public static T? ConvertTo<T>(this IConvertible convertibleValue) where T : struct
- {
- if (null == convertibleValue)
- {
- return null;
- }
- return (T?)Convert.ChangeType(convertibleValue, typeof(T));
- }
- }
|
借助于上面这个扩展方法ConvertTo,对于目标类型为Nullable<T>的转换就显得很简单了:
- int? intValue = "123".ConvertTo<int>();
- double? doubleValue = "123".ConvertTo<double>();
- DateTime? dateTimeValue = "1981-08-24".ConvertTo<DateTime>();
|
四、进一步完善扩展方法ConvertTo
上面定义的扩展方法只能完成针对目标类型为Nullable<T>的转换。现在我们来进一步完善它,让这个方法可以实现任意类型之间的转换。下面是我们新版本的ConvertTo方法的定义:
- public static T ConvertTo<T>(this IConvertible convertibleValue)
- {
- if (null == convertibleValue)
- {
- return default(T);
- }
- if (!typeof(T).IsGenericType)
- {
- return (T)Convert.ChangeType(convertibleValue, typeof(T));
- }
- else
- {
- Type genericTypeDefinition = typeof(T).GetGenericTypeDefinition();
- if (genericTypeDefinition == typeof(Nullable<>))
- {
- return (T)Convert.ChangeType(convertibleValue, Nullable.GetUnderlyingType(typeof(T)));
- }
- }
- throw new InvalidCastException(string.Format("Invalid cast from type \"{0}\" to type \"{1}\".", convertibleValue.GetType().FullName, typeof(T).FullName));
- }
|
在上面的方法中,我们首先需要确定目标类型是否是Nullable<T>,这个可以通过调用Type对象的GetGenericTypeDefinition方法来判断。如果是,则先要将其转换成对应的基本类型(Nullable<T>的泛型类型)。我们可以通过调用静态类Nullable的静态方法GetUnderlyingType来获得这个基本类型(Underlying Type)。有了这个完善版本的ConvertTo扩展方法,我们就可以进行任意的类型转化了——不论目标类型是可空值类型,还是非可空值类型:
- int intValue1 = "123".ConvertTo<int>();
- int? intValue2 = "123".ConvertTo<int?>();
- DateTime dateTimeValue1 = "1981-08-24".ConvertTo<DateTime>();
- DateTime? dateTimeValue2 = "1981-08-24".ConvertTo<DateTime?>();
|
五、谈谈NullableConverter
上面谈到TypeConverter这个类型,并且说到它具有一系列针对具体数据类型的子类。其中一个子类就是NullableConverter,故名思义,这个TypeConverter专门用于Nullable<T>的类型转换。使用该类实现针对可空值类型的转换很方便,比如:
- string literalValue = "1981-08-24";
- NullableConverter converter = new NullableConverter(typeof(DateTime?));
- DateTime? dateTimevalue = (DateTime?)converter.ConvertFromString(literalValue);
|