将Expression <func <tclass,tfield =“” >>转换为Expression <func <tclass,object =“” >>

时间:2018-07-01 11:19:07

标签: c#

我正在尝试创建一个通用的“更新表达式生成器”-一个可以传递的对象,用于指示哪些字段需要分配什么值。 我所做的是:

public class UpdateExpression<TClass> : Dictionary<Expression<Func<TClass, object>>, object> 
{};

public class  UpdateExpressionBuilder<TClass>
{
    private UpdateExpression<TClass> fieldsValues;

    public UpdateExpressionBuilder()
    {
        fieldsValues = new UpdateExpression<TClass>();
    }

    public UpdateExpressionBuilder<TClass> Add<TField>(Expression<Func<TClass, TField>> field, TField value) 
    {
        fieldsValues.Add(field, value);
        return this;
    }

    public UpdateExpression<TClass> Build()
    {
        return fieldsValues;
    }
}

应被用作:

var personUpdateExpression = new UpdateExpressionBuilder<Person>()
            .Add(p => p.FirstName, "David")
            .Add(p => p.MiddleName, "A")
            .Build();

然后我可以将personUpdateExpression作为参数发送给任何方法,例如数据库更新。

问题是呼叫fieldsValues.Add(field, value) 不编译。错误是:

error CS1503: Argument 1: cannot convert from
'System.Linq.Expressions.Expression<System.Func<TClass, TField>>' to
'System.Linq.Expressions.Expression<System.Func<TClass, object>>'

我尝试添加约束where TField : class, new() 但这并没有改变任何东西。

更改添加到的签名时 Add(Expression<Func<TClass, object>> field, object value) 它运作完美。但是,然后我松开了编译时类型检查,以便Add(p => p.FirstName, 123)可以编译,但是在运行时失败。

1 个答案:

答案 0 :(得分:1)

我完全同意Daisy在评论中写的内容...您仍然要问一些问题:

List<IRule> rules = new List<IRule>();
rules.Add(new OrdinaryRule());
rules.Add(new SpecialRule());
rules.Add(new OfferRule());
rules.Add(new FestivalRule()); //<<<

var calculator = new Calculator(rules);

var cart = new Cart(calculator);

//...

然后

public UpdateExpressionBuilder<TClass> Add<TField>(Expression<Func<TClass, TField>> field, TField value)
{
    var body = field.Body;

    // Boxing for value types
    if (typeof(TField).IsValueType)
    {
        body = Expression.Convert(body, typeof(object));
    }

    Expression<Func<TClass, object>> field2 = Expression.Lambda<Func<TClass, object>>(body, field.Parameters);

    fieldsValues.Add(field2, value);
    return this;
}

请注意,您的示例仅包含字符串,但是我为var personUpdateExpression = new UpdateExpressionBuilder<Person>() .Add(p => p.FirstName, "David") .Add(p => p.MiddleName, "A") .Add(p => p.Age, 30) .Build(); 添加了一个示例。

最后,我们重写了int。对于引用类型,除了更改Expression的返回类型外,无需执行任何其他操作。对于值类型,您需要一个明确的拳击框。