【问题标题】:Convert Expression<Func<TClass, TField>> to Expression<Func<TClass, object>>将 Expression<Func<T Class, Field>> 转换为 Expression<Func<T Class, object>>
【发布时间】:2018-07-01 11:19:07
【问题描述】:

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

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 to 的签名时 Add(Expression&lt;Func&lt;TClass, object&gt;&gt; field, object value) 它完美地工作。但是后来我放松了编译时类型检查,所以Add(p =&gt; p.FirstName, 123) 将编译,但在运行时失败。

【问题讨论】:

  • 可能值得编辑您的问题标题 - 您不是在转换代表,而是在转换表达式树。这有点不同。此外,不清楚您实际上会对生成的表达式树做什么。我怀疑您会发现您不想要 Func&lt;TClass, object&gt;,因为您需要转换回正确的字段类型。也许您应该只存储List&lt;Expression&gt;
  • (此外,您需要将表达式树转换为 fetch 一个值到 set 一个值。这可能是可行,但我会确保它适用于您打算做的事情,然后再进一步。)

标签: c#


【解决方案1】:

我完全同意 Daisy 在其 cmets 中所写的内容......您仍然要求一些东西:

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。对于引用类型,除了更改Func&lt;&gt; 的返回类型外,无需进行任何操作。对于值类型,您需要显式装箱。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多