【问题标题】:Cannot convert from `Expression<Func<T1, T2>>` to `Expression<Func<object, object>>`无法从 `Expression<Func<T1, T2>>` 转换为 `Expression<Func<object, object>>`
【发布时间】:2017-03-22 21:55:09
【问题描述】:

更新:这个问题被标记为重复,但虽然我理解代码的问题,但我没有解决方案。代码是否可以仅通过更改方法体而不更改方法签名来工作?

在尝试构建类似以下的类时,我正试图围绕ExpressionFunc 进行思考:

public class Test<TBase>
{
    private IList<Expression<Func<object, object>>> _expressions = new List<Expression<Func<object, object>>>();

    public void AddExpression<T>(Expression<Func<TBase, T>> e)
    {
        _expressions.Add(e);
    }

    public void AddExpression<T1, T2>(Expression<Func<T1, T2>> e)
    {
        _expressions.Add(e);
    }
}

我需要/想要保留一个表达式列表,Func 中的类型可能会有所不同。我虽然上面的代码可以工作,但它没有。它失败了:

Cannot convert from 'Expression&lt;Func&lt;TBase, T&gt;&gt;' to 'Expression&lt;Func&lt;object, object&gt;&gt;'

Cannot convert from 'Expression&lt;Func&lt;T1, T2&gt;&gt;' to 'Expression&lt;Func&lt;object, object&gt;&gt;'

Resharper 说:

Argument type 'Expression&lt;Func&lt;TBase, T&gt;&gt;' is not assignable to parameter type 'Expression&lt;Func&lt;object, object&gt;&gt;'

Argument type 'Expression&lt;Func&lt;T1, T2&gt;&gt;' is not assignable to parameter type 'Expression&lt;Func&lt;object, object&gt;&gt;'

是否可以只更改方法体而不更改方法签名来使代码工作?

【问题讨论】:

标签: c# generics expression


【解决方案1】:

更新:这个问题被标记为重复,但虽然我理解代码的问题,但我没有解决方案。代码是否可以仅通过更改方法体而不更改方法签名来工作?

是的,您可以保留方法签名,但您必须重写表达式...

像这样:

public void AddExpression<T1, T2>(Expression<Func<T1, T2>> e)
{
    var originalParameter = e.Parameters[0];

    // object par1
    var parameter = Expression.Parameter(typeof(object), originalParameter.Name);

    // T1 var1
    var variable = Expression.Variable(typeof(T1), "var1");

    // (T1)par1
    var cast1 = Expression.Convert(parameter, typeof(T1));

    // var1 = (T1)par1;
    var assign1 = Expression.Assign(variable, cast1);

    // The original body of the expression, with originalParameter replaced with var1
    var body = new SimpleParameterReplacer(originalParameter, variable).Visit(e.Body);

    // (object)body (a cast to object, necessary in the case T2 is a value type. If it is a reference type it isn't necessary)
    var cast2 = Expression.Convert(body, typeof(object));

    // T1 var2; var1 = (T1)par1; (object)body;
    // (the return statement is implicit)
    var block = Expression.Block(new[] { variable }, assign1, cast2);
    var e2 = Expression.Lambda<Func<object, object>>(block, parameter);

    _expressions.Add(e2);
}

我正在使用我前段时间给出的另一个回复中的SimpleParameterReplacer

最后,(T1 x) =&gt; x.Somethingx.SomethingT2)被转换为:

(object x) => 
{
    var var1 = (T1)x;
    return (object)var1.Something;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多