2016-09-23 43 views
1

我都有種以下等級:如何更改已創建的表達式?

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

我傳遞IEnumerable<Entity>>作爲數據源,以劍道電網(我覺得沒關係,倒是這裏問題clearability)。

我想實現服務器端過濾,並在網頁上實現的獨立input[text]場,並以下列方式在客戶端添加過濾器:

var grid = $(e).data('kendoGrid'); 
var columns = grid.columns; 
var columnTypes = grid.dataSource.options.schema.model.fields; 
for (var i = 0; i < columns.length; i++) { 
    if (columns[i].field) { 
     var columnDataType = columnTypes[columns[i].field].type; 
     if (columnDataType == 'number' && !isNaN(Number(value))) { 
      var filter = { field: columns[i].field, operator: "eq", value: Number(value) }; 
     } else if (columnDataType == 'string') { 
      var filter = { field: columns[i].field, operator: "contains", value: value }; 
     } 

     gridListFilter.filters.push(filter); 
    } 
} 

var gridDataSource = grid.dataSource; 
console.log(gridListFilter); 
gridDataSource.filter(gridListFilter); 

在服務器端,我有落實以下算法用於在虛擬化的處理程序方法過濾:

IQueryable<Entity> query = this.GetQuery<Entity>(); 
foreach (var item in dataSourceRequest.Filters) 
{ 
    var paramExpr = Expression.Parameter(typeof(TReturnType), "item"); 
    var expr = item.CreateFilterExpression(paramExpr); 
    var lambda = Expression.Lambda<Func<TReturnType, bool>>(expr, paramExpr); 
    query = query.Where(lambda); 
} 

其中dataSourceRequest是從Telerik的文庫DataSourceRequest類型。事項item.CreateFilterExpression產生如下表示的BinaryExpression

item => (IIF((item != null), item.Id, 0) == 6999142) OrElse 
((IIF((item != null), item.Name, null) ?? "").ToLower().Contains("6999142".ToLower())) 

其中「6999142」是搜索字符串我從視圖從input[text]得到。我想通過以下方式來修改這個表達式:

item => (IIF((item != null), item.Id, 0).ToString().Contains("6999142")) OrElse 
((IIF((item != null), item.Name, null) ?? "").ToLower().Contains("6999142".ToLower())) 

是否有更改已創建Expression無需重新創建新的一個辦法?

如果是這樣,你能否提供修改示例代碼,因爲我不知道應該從什麼開始。

+0

不,表達式樹是不可變的設計。 –

+0

@JonSkeet好吧,那麼遍歷這個表達式樹並將一些節點複製到新的表達式樹並用另一個節點替換某些節點呢?可能嗎? –

+1

是的。請參閱https://msdn.microsoft.com/en-us/library/mt654266.aspx –

回答

2

據@ JonSkeet的評論我已實現了以下

internal class KendoExpressionModifier : ExpressionVisitor 
{ 
    public Expression Modify(Expression expression) 
    { 
     return Visit(expression); 
    } 

    protected override Expression VisitConditional(ConditionalExpression node) 
    { 
     //converting result of conditional expression to string 
     return Expression.Call(node.IfTrue, typeof(object).GetMethod("ToString")); 
    } 

    protected override Expression VisitBinary(BinaryExpression node) 
    { 
     //replacing '==' operator with '.Contains' 
     if (node.NodeType == ExpressionType.Equal) 
     { 
      var left = this.Visit(node.Left); 
      var right = this.Visit(node.Right); 

      return Expression.Call(left, typeof(string).GetMethod("Contains"), right); 
     } 
     //replacing expression 'a.ToString() ?? ""' with 'a != null ? a.ToString() : ""' 
     else if (node.NodeType == ExpressionType.Coalesce) 
     { 
      var left = this.Visit(node.Left) as MethodCallExpression; 

      return Expression.Condition(
       Expression.MakeBinary(
        ExpressionType.NotEqual, 
        left.Object, 
        Expression.Constant(null)), 
       left, 
       Expression.Constant(string.Empty)); 
     } 

     return base.VisitBinary(node); 
    } 

    protected override Expression VisitConstant(ConstantExpression node) 
    { 
     //replacing constant numeric value with its string representation 
     if (node.Value.GetType() != typeof(string)) 
     { 
      return Expression.Call(node, typeof(object).GetMethod("ToString")); 
     } 

     return base.VisitConstant(node); 
    } 
} 

而且調用此修改器:

var kendoExpressionModifier = new KendoExpressionModifier(); 
expr = kendoExpressionModifier.Modify(expr); 

產生所需的結果。所以,我希望它能幫助別人。

相關問題