我之前使用過基於lamdas的C#表達式,但我沒有手工編寫它們的經驗。給定一個Expression<Func<SomeType, bool>> originalPredicate
,我想創建一個Expression<Func<OtherType, bool>> translatedPredicate
。
在這種情況下,SomeType和OtherType具有相同的字段,但它們不相關(沒有繼承而不是基於公共接口)。
背景:我有一個基於LINQ to SQL的存儲庫實現。我將LINQ to SQL實體投影到我的Model實體,以便將我的模型保存在POCO中。我想將表達式傳遞給存儲庫(作為規範的一種形式),但它們應該基於模型實體。但我無法將這些表達式傳遞給數據上下文,因為它需要基於LINQ to SQL實體的表達式。
使用Expression
,最簡單的方法是使用轉換錶達式 :
class Foo {
public int Value { get; set; }
}
class Bar {
public int Value { get; set; }
}
static class Program {
static void Main() {
Expression<Func<Foo, bool>> predicate =
x => x.Value % 2 == 0;
Expression<Func<Bar, Foo>> convert =
bar => new Foo { Value = bar.Value };
var param = Expression.Parameter(typeof(Bar), "bar");
var body = Expression.Invoke(predicate,
Expression.Invoke(convert, param));
var lambda = Expression.Lambda<Func<Bar, bool>>(body, param);
// test with LINQ-to-Objects for simplicity
var func = lambda.Compile();
bool withOdd = func(new Bar { Value = 7 }),
withEven = func(new Bar { Value = 12 });
}
}
但請注意,不同的提供商將以不同的方式支持此功能。例如,EF可能不喜歡它,即使LINQ-to-SQL也是如此。
另一種選擇是完全重建表達式樹,使用反射來找到對應的成員。更複雜。
我找到了另外一種方法,其中還包括包裝原始代表。
Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression)
{
Expression<Func<T, object>> g = obj => expression.Compile().Invoke(obj);
return g.Compile();
}