加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – Explicit Boxing之间使用Expression.Convert不能正常工作

发布时间:2020-12-15 05:41:43 所属栏目:百科 来源:网络整理
导读:最近,当我开发自制的SQLite ORM时,我遇到了一些关于使用Expression Trees进行拳击的麻烦.我还在编码C#3.5. 总而言之,我将使用这个简单的类定义: [Table]public class Michelle{ [Column(true),PrimaryKey] public UInt32 A { get; set; } [Column] public S
最近,当我开发自制的SQLite ORM时,我遇到了一些关于使用Expression Trees进行拳击的麻烦.我还在编码C#3.5.

总而言之,我将使用这个简单的类定义:

[Table]
public class Michelle
{
    [Column(true),PrimaryKey]
    public UInt32 A { get; set; }

    [Column]
    public String B { get; set; }
}

因此,根据POCO类定义,我实例化了一个新对象,我的ORM引擎将该对象转换为记录并正确插入.现在的诀窍是,当我从SQLite中获取值时,我得到了一个Int64.

我认为我的委托制定者是好的,因为它是一个Action< Object,Object>但我仍然有InvalidCastException.似乎尝试将Object(参数,Int64)强制转换为UInt32.不幸的是它不起作用.我试图添加一些Expression.Constant和Expression.TypeAs(对于值类型对象,它实际上没有帮助).

所以我想知道我的二传手生成中出了什么问题.

下面是我的setter生成方法:

public static Action<Object,Object> GenerateSetter(PropertyInfo propertyInfo)
{
    if (!FactoryFastProperties.CacheSetters.ContainsKey(propertyInfo))
    {
        MethodInfo methodInfoSetter = propertyInfo.GetSetMethod();
        ParameterExpression parameterExpressionInstance = Expression.Parameter(FactoryFastProperties.TypeObject,"Instance");
        ParameterExpression parameterExpressionValue = Expression.Parameter(FactoryFastProperties.TypeObject,"Value");

        UnaryExpression unaryExpressionInstance = Expression.Convert(parameterExpressionInstance,propertyInfo.DeclaringType);
        UnaryExpression unaryExpressionValue = Expression.Convert(parameterExpressionValue,propertyInfo.PropertyType);

        MethodCallExpression methodCallExpression = Expression.Call(unaryExpressionInstance,methodInfoSetter,unaryExpressionValue);

        Expression<Action<Object,Object>> expressionActionObjectObject =  Expression.Lambda<Action<Object,Object>>(methodCallExpression,new ParameterExpression[] { parameterExpressionInstance,parameterExpressionValue });

        FactoryFastProperties.CacheSetters.Add(propertyInfo,expressionActionObjectObject.Compile());
    }

    return FactoryFastProperties.CacheSetters[propertyInfo];
}

所以基本上:

// Considering setter as something returned by the generator described above
// So:

// That one works!
setter(instance,32u);

// This one... hm not really =/
setter(instance,64);

我应该添加另一个Expression.Convert,但我真的不知道如何使它工作.因为已经有人应该(尝试)从任何Object转换为属性类型(在我的例子中是UInt32类型).

有什么想法解决它吗?

解决方法

对于这个答案,假设定义如下:
object myColValueFromTheDatabase = (object)64L;

Expression.Convert静态地确定如何执行转换.就像C#一样.如果您编写(uint)myColValueFromTheDatabase,这将无法在运行时成功,因为取消装箱只是不起作用. Expression.Convert也做了一个简单的拆箱尝试.这就是它失败的原因.

您需要执行以下任一操作:

>(uint)(long)myColValueFromTheDatabase
> Convert.ToUInt32(myColValueFromTheDatabase)

在情况(1)中,您需要首先取消装箱到完全匹配类型,然后更改位.案例(2)使用一些辅助方法解决了这个问题.案例(1)更快.

要使用表达式API执行此操作,请插入另一个Expression.Convert.

这应该让你开始:

public static T LogValue<T>(T val)
    {
        Console.WriteLine(val.GetType().Name + ": " + val);
        return val;
    }
    static void Main(string[] args)
    {
        Expression myColValueFromTheDatabase = Expression.Convert(Expression.Constant(1234L),typeof(object));
        myColValueFromTheDatabase = Expression.Call(typeof(Program),"LogValue",new[] { myColValueFromTheDatabase.Type },myColValueFromTheDatabase); //log
        Expression unboxed = Expression.Convert(myColValueFromTheDatabase,typeof(long));
        Expression converted = Expression.Convert(unboxed,typeof(uint));

        var result = Expression.Lambda<Func<uint>>(converted).Compile()();
        Console.WriteLine(result);
    }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读