首页 新闻 会员 周边

表达式树实现long到int的转换,报告转换失败

0
悬赏园豆:10 [已解决问题] 解决于 2016-02-25 16:58
    var paramValue = Expression.Parameter(typeof(object));var bodyValue = Expression.Convert(paramValue, typeof(int));
    var b = Expression.Lambda(bodyValue, paramValue).Compile();
    var br = b.DynamicInvoke(2L);//此处抛出异常

 

519740105的主页 519740105 | 大侠五级 | 园豆:5810
提问于:2016-02-25 15:01
< >
分享
最佳答案
0

去掉L,这个类似:

object o = 2L;
int ii = (int)o;

收获园豆:10
jello chen | 大侠五级 |园豆:7306 | 2016-02-25 15:19

没办法处理的。

 

我的需求是:

 

对象被json序列化,然后再反序列化,得到一个字典,字典中,Age的值会从 int 变成 long。

我这个代码的目的就是把字典的值转换为对象的属性值。

519740105 | 园豆:5810 (大侠五级) | 2016-02-25 15:22

@519740105: 那就把object写成long

jello chen | 园豆:7306 (大侠五级) | 2016-02-25 15:24

@519740105: 或者Expression Call Convert.ToInt32()

jello chen | 园豆:7306 (大侠五级) | 2016-02-25 15:27

@jello chen: 具体的类型不确定,所以需要用object。

我的实际需求场景是:

定义一个可扩展实体,该实体具备一个可扩展的数据属性(类似于复杂数据类型)

当把这个实体存储于数据库时,可扩展数据属性的内容通过json格式存储,当从数据库读取时,将json转换为字典,逐个识别扩展数据属性对象属性定义,然后把内容填写上。

519740105 | 园豆:5810 (大侠五级) | 2016-02-25 15:28

@jello chen: 在进行数据写时,本来也可以通过GetValue或SetValue来实现,考虑到性能,便想到了用ExpressionTree。

事实上,当使用Action<object, object>设置值时,因value是long,也需要经过转换,此时使用Expression.Convert是能转换成功。但是,通过Expression的多次转换就出现了这个问题。

519740105 | 园豆:5810 (大侠五级) | 2016-02-25 15:31

@jello chen: 

public static Action<object, object> MakeSetLambda(this PropertyInfo propertyInfo, Type declaringType = null)
{
    var paramInst = Expression.Parameter(typeof(object));
    var paramValue = Expression.Parameter(typeof(object));
    var bodyInst = Expression.Convert(paramInst, declaringType ?? propertyInfo.DeclaringType);
    var bodyValue = Expression.Convert(paramValue, propertyInfo.PropertyType);
    var bodyExp = Expression.Call(bodyInst, propertyInfo.GetSetMethod(), bodyValue);
    var result = Expression.Lambda<Action<object, object>>(bodyExp, paramInst, paramValue).Compile();
    return result;
}

模拟调用:

PropertyInfo propertyInfo = typeof(Test).GetProperty("Age");
var setter = MakeSetLambda(propertyInfo);
object age = 2L;
object instance = new Test();
setter(instance, age);//此处抛出异常
519740105 | 园豆:5810 (大侠五级) | 2016-02-25 15:35

@519740105: 嗯,改成这样试试:

var bodyValue = Expression.Convert(paramValue, typeof(int), typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(object) }));

jello chen | 园豆:7306 (大侠五级) | 2016-02-25 15:38

@jello chen: 关键是这个 int 是不确定的。现在只是发现了long到int出现了问题。代码还得按照我的思路来。

519740105 | 园豆:5810 (大侠五级) | 2016-02-25 15:39

@519740105: 胡乱写了下:

public static Action<object, object> MakeSetLambda(this PropertyInfo propertyInfo, Type declaringType = null)
        {
            var paramInst = Expression.Parameter(typeof(object));
            var paramValue = Expression.Parameter(typeof(object));
            var type = declaringType ?? propertyInfo.DeclaringType;
            var bodyInst = Expression.Convert(paramInst, type);
            var bodyValue = Expression.Convert(paramValue, propertyInfo.PropertyType, GetConvertMethodInfo(propertyInfo.PropertyType));
            var bodyExp = Expression.Call(bodyInst, propertyInfo.GetSetMethod(), bodyValue);
            var result = Expression.Lambda<Action<object, object>>(bodyExp, paramInst, paramValue).Compile();
            return result;
        }

        static MethodInfo GetConvertMethodInfo(Type type)
        {
            //可缓存
            var typeCode = TypeInfo.GetTypeCode(type);
            var mi = typeof(Convert).GetMethod("To" + typeCode, new Type[] { typeof(object) });
            return mi;
        }
jello chen | 园豆:7306 (大侠五级) | 2016-02-25 16:23

@jello chen: 恩,这也是一个办法。但是,就不能把我的这个 MakeStLambda 作为通用的 方法了。

我再想想。

519740105 | 园豆:5810 (大侠五级) | 2016-02-25 16:46
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册