2017-03-22 67 views
1

UPDATED:这个问题被标记为重复,但虽然我理解代码的问题,但是我没有解。代码是否可以仅通过更改方法体而不是方法签名来工作?不能从`Expression <Func<T1, T2>>`转换为`Expression <Func <object,object >>`

我绑来包装我的周围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<Func<TBase, T>>' to 'Expression<Func<object, object>>'

Cannot convert from 'Expression<Func<T1, T2>>' to 'Expression<Func<object, object>>'

ReSharper的说:

Argument type 'Expression<Func<TBase, T>>' is not assignable to parameter type 'Expression<Func<object, object>>'

Argument type 'Expression<Func<T1, T2>>' is not assignable to parameter type 'Expression<Func<object, object>>'

代码是否可以通过仅更改方法体而不是方法签名来工作?

+4

'Func键'是仅在'TResult'协变,因为这是输出,但逆变在'T'因为这是输入。所以如果你有一个'Func ','string'可以被转换成'object',但是你不能只传递任何'object'到'int'中。 https://msdn.microsoft.com/zh-cn/library/dd799517(v=vs.110).aspx – juharr

+0

与http://stackoverflow.com/q/42951537/613130非常相似,但增加了复杂性需要转换参数和返回值。 – xanatos

回答

2

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

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

像这样:

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) => x.Something(具有x.Something被一个T2)是在转化的:

(object x) => 
{ 
    var var1 = (T1)x; 
    return (object)var1.Something; 
} 
相关问题