![](/img/trans.png)
[英]How to convert LambdaExpression to Expression<Func<T,bool>> in C#
[英]C# How to convert an Expression<Func<SomeType>> to an Expression<Func<OtherType>>
我以前使用過基於 lamda 的 C# 表達式,但我沒有手工編寫它們的經驗。 給定一個Expression<Func<SomeType, bool>> originalPredicate
,我想創建一個Expression<Func<OtherType, bool>> translatedPredicate
。
在這種情況下, SomeType 和 OtherType 具有相同的字段,但它們不相關(沒有 inheritance 並且不基於公共接口)。
背景:我有一個基於 LINQ 到 SQL 的存儲庫實現。我將 LINQ 到 SQL 實體投影到我的 Model 實體,以將我的 model 保留在 POCO 中。 我想將表達式傳遞給存儲庫(作為規范的一種形式),但它們應該基於 model 實體。 但我無法將這些表達式傳遞給數據上下文,因為它需要基於 LINQ 到 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();
}
沒有隱含的方式來進行翻譯。 您必須將現有委托包裝在 lambda 中,該委托從參數類型創建新類型:
var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x))
其中OtherTypeFromSomeType
從SomeType
參數創建OtherType
實例。
就我而言,我遇到了同樣的不便,問題是我使用 AutoMapper 將信息從一個 class 傳遞到另一個,在這種情況下,@Marc-Gravell 的解決方案不適用於我的 AutoMapper,但做了一些研究我發現AutoMapper 可以將Expression<Func<OrderLineDTO, bool>>
轉換為Expression<Func<OrderLine, bool>>
public class OrderLine
{
public int Id { get; set; }
public int OrderId { get; set; }
public decimal Quantity { get; set; }
}
public class OrderLineDTO
{
public int Id { get; set; }
public int OrderId { get; set; }
public decimal Quantity { get; set; }
}
AutoMapper 配置如下
var config = new MapperConfiguration(cfg =>
{
cfg.AddExpressionMapping();
cfg.CreateMap<OrderLine, OrderLineDTO>();
cfg.CreateMap<OrderLineDTO, OrderLine>();
});
var mapper = config.CreateMapper();
最后,執行轉換
Expression<Func<OrderLineDTO, bool>> expression = e => e.OrderId == 102;
Expression<Func<OrderLine, bool>> convertedExpression = mapper.Map<Expression<Func<OrderLine, bool>>>(expression);
此代碼依賴於AutoMapper
和AutoMapper.Extensions.ExpressionMapping
有關詳細信息,您可以查看AutoMapper的文檔並執行表達式
我和你有同樣的問題,我用 EF 解決了這個問題:
var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>>
實體框架知道如何構建正確的 sql 命令。 轉換表達式要復雜得多,因為它是不可變的,如果你做錯了什么,可能會導致不希望的運行時效果,至少在我的情況下,它是不需要的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.