2016-10-11 83 views
-1

我想創建一個LINQ表達式選擇器來容納另一個IQueryable作爲參數。該dot.net小提琴是here表達式<Func <TSource,TResult >>選擇器與參數

我試圖代碼的CustomSelector接受的IQueryable parameter並將其應用到視情況選擇。

另外,我想包含在調用CustomSelector將每行的值應用於IQueryable參數。

這樣我就不必編寫2個自定義選擇器。

替代方案是GetMyData2函數。

測試代碼如下:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

public class Entity 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class EntityDto 
{ 
    public int Id { get; set; } 
    public string Name { get; set; }  
    public int Count { get; set; } 
} 

public class TestController 
{ 
    public List<Entity> entityList { get; set; } 


    public List<EntityDto> GetMyData(string condition) 
    { 
     List<Entity> sourceEntityList = new List<Entity>(); 
     List<EntityDto> returnEntityList = new List<EntityDto>(); 

     switch(condition) 
     { 
      case "A":  
      returnEntityList = sourceEntityList.Where(x=>x.Name == "A").Select(y=>CustomSelector(sourceEntityList.Where(z=>z.Name=x.Name))); 
     return returnEntityList; 
      break; 
     case "B":  
     default: 
      returnEntityList = sourceEntityList.Where(x=>x.Name == "B").Select(y=>CustomSelector(sourceEntityList.Where(z=>z.Name != x.Name))); 
     return returnEntityList; 
      break; 
     } 

    } 

    public List<EntityDto> GetMyData2(string condition) 
    { 
     List<Entity> sourceEntityList = new List<Entity>(); 
     List<EntityDto> returnEntityList = new List<EntityDto>(); 

     switch(condition) 
     { 
      case "A":  
      returnEntityList = sourceEntityList.Where(x=>x.Name == "A").Select(ent=> 
                       new EntityDto() 
       { 
        Id = ent.Id 
        , 
        Name = ent.Name          
        , 
        Count = sourceEntityList.Count(z=>z.Name== ent.Name) 
       } 
                      ).ToList(); 
     return returnEntityList; 
      break; 
     case "B":  
     default: 
      returnEntityList = sourceEntityList.Where(x=>x.Name == "B").Select(ent=> 
                       new EntityDto() 
       { 
        Id = ent.Id 
        , 
        Name = ent.Name          
        , 
        Count = sourceEntityList.Count(z=>z.Name != ent.Name) 
       } 
                      ).ToList(); 
     return returnEntityList; 
      break; 
     } 

    } 

    protected Func<Entity, EntityDto> CustomSelector(IQueryable<Entity> paramQuery) 
     { 

       return ent => new EntityDto() 
       { 
        Id = ent.Id 
        , 
        Name = ent.Name          
        , 
        Count = paramQuery.Count() 
       }; 

     } 
} 
+0

而你的問題是... –

+0

如何創建一個LINQ表達式選擇器來容納另一個IQueryable作爲參數? –

回答

1

什麼是你問的是不可能的W/O一些表達式樹操作。

你可以使用一些第三方包,比如LinqKitAsExpandable/Invoke)或AutoMapper,但這裏是基於表達式的原型和簡單的參數替代品的定製解決方案。

參數替代品:

public static class ExpressionUtils 
{ 
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target) 
    { 
     return new ParameterReplacer { Source = source, Target = target }.Visit(expression); 
    } 

    class ParameterReplacer : ExpressionVisitor 
    { 
     public ParameterExpression Source; 
     public Expression Target; 
     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      return node == Source ? Target : base.VisitParameter(node); 
     } 
    } 
} 

CustomSelector:

protected Expression<Func<Entity, EntityDto>> CustomSelector(Expression<Func<Entity, IQueryable<Entity>>> paramQuery) 
{ 
    Expression<Func<Entity, IQueryable<Entity>, EntityDto>> prototype = (e, q) => new EntityDto 
    { 
     Id = e.Id, 
     Name = e.Name, 
     Count = q.Count(), 
    }; 
    return Expression.Lambda<Func<Entity, EntityDto>>(
     prototype.Body 
      .ReplaceParameter(prototype.Parameters[0], paramQuery.Parameters[0]) 
      .ReplaceParameter(prototype.Parameters[1], paramQuery.Body), 
     paramQuery.Parameters[0]); 
} 

用法:

public List<EntityDto> GetMyData(string condition) 
{ 
    var sourceEntityList = new List<Entity>().AsQueryable(); 
    switch (condition) 
    { 
     case "A": 
      return sourceEntityList.Where(x => x.Name == "A") 
       .Select(CustomSelector(x => sourceEntityList.Where(y => y.Name == x.Name))).ToList(); 
     case "B": 
     default: 
      return sourceEntityList.Where(x => x.Name == "B") 
       .Select(CustomSelector(x => sourceEntityList.Where(y => y.Name != x.Name))).ToList(); 
    } 
} 
+0

謝謝你的回答。 不知道爲什麼downvotes雖然,他們沒有留下評論。 因此,我只會爲每種情況編寫不同的選擇器,這會更好嗎? –

+0

我不太確定我是否瞭解每個案例的最後一個問題。該示例僅顯示一個「CustomSelector」方法,答案也是如此。 –

+0

也許一次替換所有參數(如'prototype.Body.BetaReduce(paramQuery.Parameters [0],paramQuery.Body)')會更漂亮嗎? –

相關問題