下面是使用AutoMapper一個解決方案:
Func<Cat, bool> GetMappedSelector(Func<Dog, bool> selector)
{
Func<Cat, Dog> mapper = Mapper.CreateMapExpression<Cat, Dog>().Compile();
Func<Cat, bool> mappedSelector = cat => selector(mapper(cat));
return mappedSelector;
}
UPDATE:它已經1.5年因爲我第一次回答了這一點,我想我會在我的答案擴大,因爲現在人們都在問如何做到這一點當你有一個表達式而不是一個委託。
解決方案原則上相同 - 我們需要能夠將compose這兩個函數(selector
和mapper
)合併爲一個函數。不幸的是,由於C#沒有辦法從另一個表達式中調用一個表達式(就像我們可以用委託),我們不能直接在代碼中表示它。例如,下面的代碼將無法編譯:
Expression<Func<Cat, bool>> GetMappedSelector(Expression<Func<Dog, bool>> selector)
{
Expression<Func<Cat, Dog>> mapper = Mapper.CreateMapExpression<Cat, Dog>();
Expression<Func<Cat, bool>> mappedSelector = cat => selector(mapper(cat));
return mappedSelector;
}
創造我們組成功能的唯一途徑,因此,這是我們自己使用System.Linq.Expressions
類建立了expression tree。
我們真正需要做的是修改selector
函數的主體,使其參數的所有實例都被mapper
函數的主體替換。這將成爲我們新功能的主體,它將接受mapper
的參數。
要更換我創建ExpressionVisitor類的子類,可以遍歷一個表達式樹,並用任意表達式替換單個參數的參數:
class ParameterReplacer : ExpressionVisitor
{
private ParameterExpression _parameter;
private Expression _replacement;
private ParameterReplacer(ParameterExpression parameter, Expression replacement)
{
_parameter = parameter;
_replacement = replacement;
}
public static Expression Replace(Expression expression, ParameterExpression parameter, Expression replacement)
{
return new ParameterReplacer(parameter, replacement).Visit(expression);
}
protected override Expression VisitParameter(ParameterExpression parameter)
{
if (parameter == _parameter)
{
return _replacement;
}
return base.VisitParameter(parameter);
}
}
然後創建一個擴展方法,Compose()
,使用該訪客撰寫兩封lambda表達式,外部和內部:現在
public static class FunctionCompositionExtensions
{
public static Expression<Func<X, Y>> Compose<X, Y, Z>(this Expression<Func<Z, Y>> outer, Expression<Func<X, Z>> inner)
{
return Expression.Lambda<Func<X ,Y>>(
ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body),
inner.Parameters[0]);
}
}
,並在所有的地方基礎設施,我們可以修改GetMappedSelector()
方法來使用我們的Compose()
分機:
Expression<Func<Cat, bool>> GetMappedSelector(Expression<Func<Dog, bool>> selector)
{
Expression<Func<Cat, Dog>> mapper = Mapper.CreateMapExpression<Cat, Dog>();
Expression<Func<Cat, bool>> mappedSelector = selector.Compose(mapper);
return mappedSelector;
}
我創建了一個simple console application測試了這一點。希望我的解釋不會太模糊;但不幸的是,做你正在做的事情並不是一個簡單的方法。如果您仍然完全困惑,至少您可以重複使用我的代碼,並且已經瞭解處理表達樹的細微差別和複雜性!
什麼?如果我有這樣的: 公共IEnumerable的(表達> predicate) var x = dbo.Products.Get(ExpressionMapper.GetMappedSelector (predicate);) } 它只適用於Func 不與Expression > –
@ persianDev你能找到一種方法來做到這一點?我有同樣的問題。 –
@bahadirarslan我更新瞭解決此問題的答案。 – luksan