技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 算法 --> 当类型转换表达式遇上自定义转换操作

当类型转换表达式遇上自定义转换操作

浏览:1480次  出处信息

    之前我提到说System.Json是一个十分不好用的类库,其中一点就是在于,我没法将一个JsonValue转化为范型类型――它只为Int32,String等几种特定类型定义了隐式转换,又无法得到以object类型所引用的值。不过这也难不到拥有“在运行时创建自定义表达式树并编译成动态代码”的.NET程序员。例如我们可以写这样一个辅助类进行JsonValue至任意类型的转化操作,.NET类库会负责为我们选择合适的转换方式:

class JsonConverter
{
    static JsonConverter()
    {
        var jsonValueExpr = Expression.Parameter(typeof(JsonValue), "jsonValue");
        var convertExpr = Expression.Convert(jsonValueExpr, typeof(T));
        var lambdaExpr = Expression.Lambda>(convertExpr, jsonValueExpr);
        s_convert = lambdaExpr.Compile();
    }

    private static Func s_convert;

    public static T Convert(JsonValue jsonValue)
    {
        return s_convert(jsonValue);
    }
}

    泛型参数字典和动态代码生成都是性能的有效保证,而构造一颗我们需要的表达式树也十分容易。这个方法我以前也谈起过,我认为每个称职的.NET程序员都应该熟练掌握这种“通用操作”的实现方式。不过我最近在构造这种类型转换表达式的时候遇到了一些问题。例如,如果我们需要构造一个表达式,将一个JsonPrimitive(而不是先前的JsonValue)转化为int,这便会抛出一个异常,提示我们“没有合适的强制转化方式”。

    我猜,可能是因为那些隐式转化操作定义在JsonValue上吧。那么这算不算一个Bug?我认为是,因为与它等价的代码是没有任何问题的,例如:

var value = (int)(new JsonPrimitive(10));

    C#编译器会为我们找到JsonValue上定义的op_Implict方法并生成调用代码,而.NET类库却不会这么做,双方配合不够默契。不过其实这很容易绕开,只是我们要将这样的代码:

var convertExpr = Expression.Convert(instanceExpr, targetType);

    修改为:

static Expression GetConvertExpression(Expression instanceExpr, Type targetType)
{
    var mediateType = instanceExpr.Type;

    if (mediateType == typeof(object))
    {
        // (TargetType)instance
        return Expression.Convert(instanceExpr, targetType);
    }

    while (mediateType != typeof(object))
    {
        try
        {
            // (MediateType)instace
            var mediateExpr = Expression.Convert(instanceExpr, mediateType);
            // (TargetType)(MediateType)instance
            return Expression.Convert(mediateExpr, targetType);
        }
        catch
        {
            mediateType = mediateType.BaseType;
        }
    }

    throw new Exception(...);
}

    我们选择的策略很简单,提供一个“过渡类型”,先将instance转换为过渡类型,再转换成目标类型。如果发生转换错误,则会继续尝试其父类,直至object类型为止,则抛出异常表示转换失败。目前看来这个做法并没有什么问题。

建议继续学习:

  1. STRUTS2类型转换错误导致OGNL表达式注入漏洞分析    (阅读:8920)
  2. PHP数据类型隐性转换的陷阱    (阅读:2838)
  3. javascript运算/转换技巧    (阅读:2682)
  4. JavaScript ( (__ = !$ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] )    (阅读:2566)
  5. 编写安全代码:再论整数类型转换    (阅读:2513)
  6. 弱类型?C语言参数提升带来的一个陷阱    (阅读:2119)
  7. PHP类型转换相关的一个Bug    (阅读:1930)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1