2017-03-22 97 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; 
} 
相關問題