如何使用Expression.Assign选择器和目标类型的对象一般分配属性?

时间:2012-10-10 14:06:20

标签: c# .net-4.0 expression

我正在尝试使用表达式选择器一般将属性从一种类型的对象分配给另一种属性属于各种类型的对象。这是我到目前为止的代码:

var type1 = new Type1();
var type2 = new Type2();

...

var propMap = new List<Tuple<Expression<Func<Type1, object>>, Expression<Func<TradeStaticAttributesItemModel, object>>>>
    {
        new Tuple<Expression<Func<Type1, object>>, Expression<Func<Type2, object>>>(x => x.Prop1, x => x.Prop1),
        new Tuple<Expression<Func<Type1, object>>, Expression<Func<Type2, object>>>(x => x.Prop2, x => x.Prop2)
    };

foreach (var prop in propMap)
{
    if (prop.Item1.Compile()(type1) != prop.Item2.Compile()(type2))
    {
        ParameterExpression valueParameterExpression = Expression.Parameter(prop.Item2.Body.Type);
        var assign = Expression.Lambda<Action<Type1, object>>(Expression.Assign(prop.Item1.Body, valueParameterExpression), prop.Item1.Parameters.Single(), valueParameterExpression);
        Action<Type1, object> setter = assign.Compile();
        setter(type1, prop.Item2.Compile()(type2));
    }
}

然而,我是,但是,我收到错误“类型'System.String'的ParameterExpression'不能用于'System.Object'类型的委托参数”属性的类型是string。我想除object以外的任何其他类型也会发生这种情况。知道如何使这个代码适用于这种情况吗?

我使用Expression.Convert找到了一个潜在的答案here,但我无法让它发挥作用。

1 个答案:

答案 0 :(得分:4)

好的,我使用以下代码:

var type1 = new Type1();
var type2 = new Type2();

...

var propMap = new List<Tuple<Expression<Func<Type1, object>>, Expression<Func<TradeStaticAttributesItemModel, object>>>>
    {
        new Tuple<Expression<Func<Type1, object>>, Expression<Func<Type2, object>>>(x => x.Prop1, x => x.Prop1),
        new Tuple<Expression<Func<Type1, object>>, Expression<Func<Type2, object>>>(x => x.Prop2, x => x.Prop2)
    };

foreach (var prop in propMap)
{
    if (prop.Item1.Compile()(type1) != prop.Item2.Compile()(type2))
    {
        ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object));

        // This handles nullable types
        Expression targetExpression = prop.Item1.Body is UnaryExpression ? ((UnaryExpression)prop.Item1.Body).Operand : prop.Item1.Body;

        var assign = Expression.Lambda<Action<Type1, object>>(
            Expression.Assign(targetExpression, Expression.Convert(valueParameterExpression, targetExpression.Type)),
            prop.Item1.Parameters.Single(),
            valueParameterExpression);

        Action<Type1, object> setter = assign.Compile();
        setter(type1, prop.Item2.Compile()(type2));
    }
}

这适用于可空类型(如注释)。我现在知道Expression了,但如果有人对此代码有任何改进,请随时提出建议!