通用类型转换方法

在编程中,类型转换是一个常见的需求,但每种技术都有其局限性。本文提供了一种在CLR能够执行类型转换时,适用于所有情况的替代方案。

在类型转换的问题上,有两种流行的解决方案:使用System.Convert.ChangeType,或者获取System.ComponentModel.TypeConverter并调用其ConvertFrom方法。第一种方法在尝试将值类型T转换为System.Nullable时会失败;第二种方法在尝试转换不同的数值类型时,例如从float转换到double时也会失败。这些限制特别令人沮丧,因为CLR内置了执行这两种转换的能力。

一种利用这些类型转换能力的方法是构建一个LINQlambda表达式,将其编译为Func,然后每次需要在两种类型之间转换时使用编译后的委托。下面是一个实现这种方法的代码示例,它被封装成了System.Type扩展方法

public static class TypeCast { // 这是暴露其余功能的方法 public static object Cast(this Type type, object obj) { return GetConverter(type, obj)(obj); } private static readonly IDictionary> converters = new Dictionary>(); private static readonly ParameterExpression convParameter = Expression.Parameter(typeof(object), "val"); // 这是实现的"核心"方法 [MethodImpl(MethodImplOptions.Synchronized)] private static Func GetConverter(Type targetType, object val) { var fromType = val != null ? val.GetType() : typeof(object); var key = new PairOfTypes(fromType, targetType); Func res; if (converters.TryGetValue(key, out res)) { return res; } res = (Func)Expression.Lambda( Expression.Convert( Expression.Convert( Expression.Convert( convParameter, fromType ), targetType ), typeof(object) ), convParameter ).Compile(); converters.Add(key, res); return res; } // 这个类为System.Type对象对提供Equals和GetHashCode private class PairOfTypes { private readonly Type first; private readonly Type second; public PairOfTypes(Type first, Type second) { this.first = first; this.second = second; } public override int GetHashCode() { return 31 * first.GetHashCode() + second.GetHashCode(); } public override bool Equals(object obj) { if (obj == this) { return true; } var other = obj as PairOfTypes; if (other == null) { return false; } return first.Equals(other.first) && second.Equals(other.second); } } } double? x = typeof(double?).Cast(1.0); int y = typeof(int).Cast(1.2345);
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485