65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 LINQ 进行类型转换

starIconstarIconstarIconstarIconstarIcon

5.00/5 (14投票s)

2010年2月25日

CPOL
viewsIcon

57125

.NET 中的类型转换

引言

.NET 提供了几种在运行时将值类型转换为另一种类型的方法。每种技术都有其局限性。本文提供(又一个)替代方案,当 CLR 能够执行类型转换时,它都适用。

背景

解决类型转换问题的两种流行方法是使用 System.Convert.ChangeType,或获取 System.ComponentModel.TypeConverter 并调用其 ConvertFrom 方法。第一种方法在尝试将值类型 T 转换为 System.Nullable<T> 时会出错;第二种方法在尝试转换不同的数值类型时会出错,例如,将 float 转换为 double。这些限制尤其令人沮丧,因为 CLR 具有内置的功能来执行这两种类型的转换。

一种利用这些类型转换功能的方法是构建一个 LINQ lambda 表达式,将其 编译Func<object,object>,然后在每次需要在这两种类型之间转换时使用编译后的委托。

Using the Code

以下代码实现了这种方法,将其包装到 System.Type 的扩展方法中。

public static class TypeCast {
    // This is the method exposing the rest of the functionality
    public static object Cast(this Type type, object obj) {
        return GetConverter(type, obj)(obj);
    }
    private static readonly IDictionary<PairOfTypes,Func<object,object>> converters =
        new Dictionary<PairOfTypes,Func<object,object>>();
    private static readonly ParameterExpression convParameter =
        Expression.Parameter(typeof(object), "val");
    // This is the method with the "guts" of the implementation
    [MethodImpl(MethodImplOptions.Synchronized)]
    private static Func<object,object> GetConverter(Type targetType, object val) {
        var fromType = val != null ? val.GetType() : typeof(object);
        var key = new PairOfTypes(fromType, targetType);
        Func<object,object> res;
        if (converters.TryGetValue(key, out res)) {
            return res;
        }
        res = (Func<object,object>)Expression.Lambda(
            Expression.Convert(
                Expression.Convert(
                    Expression.Convert(
                        convParameter
                    ,   fromType
                    )
                ,   targetType
                )
            ,   typeof(object)
            )
        ,   convParameter
        ).Compile();
        converters.Add(key, res);
        return res;
    }
    // This class provides Equals and GetHashCode
    // for a pair of System.Type objects.
    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);
        }
    }
}

现在,您可以像这样使用 Cast 方法

double? x = typeof(double?).Cast(1.0);
int y = typeof(int).Cast(1.2345);

祝您编码愉快!

© . All rights reserved.