簡體   English   中英

是清單 <T> 表達式樹中的常量,表達式參數或其他內容?

[英]Is List<T> a constant, an expression parameter, or something else in Expression Tree?

假設我有一個lambda表達式,我想在上面寫一個表達式Tree:

query.Where(d => (allCk && d.FacilityId == facilityId) //1.
      ||
     (!allCk && allSelected && d.FacilityId == facilityId  && !ids.Contains(d.Id)) //2.
      ||
     (!allCk && !allSelected && ids.Contains(d.Id))) //3.

這是我設法編寫的方式:為簡潔起見,我僅顯示第二個條件,它是所有條件中最復雜的(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id))

private Expression<Func<Documents, bool>> GetDocumentsPredicate(
        int facilityId, bool allCk, bool allSelected, List<int> ids)
{
  ParameterExpression pe = Expression.Parameter(typeof(Documents), "d");

  var listExpr1 = new List<Expression>();
  listExpr1.Add(Expression.IsFalse(Expression.Constant(allCk)));  //allCk
  listExpr1.Add(Expression.Constant(allSelected));                //allSelected

  var facilityParam = Expression.Constant(facilityId);            //facility
  Expression facilityIdProp = Expression.Property(pe, "FacilityId");
  Expression facilityIdEql = Expression.Equal(facilityIdProp, facilityParam);
  listExpr1.Add(facilityIdEql);

  //This is where I'm having trouble... Is ids a parameter or a constant???
  //Assuming it's a parameter...

  ParameterExpression peIds = Expression.Parameter(typeof(List<int>), "ids");
  Expression listContains = Expression.Call(
           pIds,
           typeof(List<int>).GetMethod("Contains"),
           Expression.Property(pe, "Id"));
  listExpr1.Add(Expression.Call(peIds, listContains, Expression.Property(pe, "Id"))); 
  var exp1 = listExpr1
             .Skip(1)
             .Aggregate(listExpr1[0], Expression.AndAlso);

  //...

}

我在此行遇到錯誤: listExpr1.Add(Expression.Call(pIds, listContains, Expression.Property(pe, "Id"))); //無法將“ Linq.Expression.ParameterExpression”轉換為“ System.Reflection.MethodInfo”`。 因此,它正在抱怨pIds

那么,這里的id是什么,常量,參數還是其他?

感謝您的幫助

編輯

這就是我寫整個方法的方式

private Expression<Func<Documents, bool>> GetDocumentsPredicate(
    int facilityId, bool allCk, bool allSelected, List<int> ids)
{
  ParameterExpression pe = Expression.Parameter(typeof(Document), "d");
  Expression constIds = Expression.Constant(ids);
  Expression allCkParam = Expression.Constant(allCk);
  Expression allSelectedParam = Expression.Constant(allSelected);

  Expression listContains = Expression.Call(
           constIds,
           typeof(List<int>).GetMethod("Contains"),
           Expression.Property(pe, "Id"));

  /*(allCk && d.FacilityId == facilityId) ==> exp0*/
  var facilityParam = Expression.Constant(facilityId);


  Expression facilityIdProp = Expression.Property(pe, "FacilityId");
  Expression facilityIdEql = Expression.Equal(facilityIdProp, facilityParam);

  Expression exp0 = Expression.AndAlso(allCkParam, facilityIdEql);

/*(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id))) 
  ==> exp1 */
  var listExpr1 = new List<Expression>();
  listExpr1.Add(Expression.IsFalse(allCkParam));
  listExpr1.Add(allSelectedParam);
  listExpr1.Add(facilityIdEql);
  listExpr1.Add(Expression.IsFalse(listContains));

  var exp1 = listExpr1
            .Skip(1)
            .Aggregate(listExpr1[0], Expression.AndAlso);


   /* (!allCk && !allSelected && ids.Contains(d.Id)) ==> exp2 */
   var listExpr2 = new List<Expression>();
   listExpr2.Add(Expression.IsFalse(allCkParam));
   listExpr2.Add(Expression.IsFalse(allSelectedParam));
   listExpr1.Add(listContains);

   var exp2 = listExpr2
            .Skip(1)
            .Aggregate(listExpr2[0], Expression.AndAlso);

   var listExpr = new List<Expression> { exp0, exp1, exp2 };
   var exp = listExpr
            .Skip(1)
            .Aggregate(listExpr[0], Expression.OrElse);

    var expr = 
              Expression.Lambda<Func<Document, bool>>(exp, 
              new ParameterExpression[] { pe });
    return expr;
 }

這是我將鼠標懸停在返回值上時得到的結果

d => (((False AndAlso (d.FacilityId == 1)) 
     OrElse 
     (((IsFalse(False) AndAlso False) AndAlso (d.FacilityId == 1)) 
        AndAlso 
        IsFalse(value(System.Collections.Generic.List`1[System.Int32]).Contains(d.Id)))) 
     OrElse 
    ((IsFalse(False) AndAlso IsFalse(False)) 
        AndAlso 
        value(System.Collections.Generic.List`1[System.Int32]).Contains(d.Id)))

使用此語句的簡單測試var count = query.Count(); 產生一個異常: Unknown LINQ expression of type 'IsFalse'

讓我們總結一下。 您在此調用上收到過載解析錯誤:

Expression.Call(peIds, listContains, Expression.Property(pe, "Id"))

peIdsParameterExpression類型。 listContains的類型為Expression 第三個參數是MemberExpression類型。

現在,查看Expression.Call的重載列表。 這些都不符合這三個參數。

編譯器的最佳猜測是您正在嘗試調用此代碼:

https://msdn.microsoft.com/zh-CN/library/dd324092(v=vs.110).aspx

因此出現錯誤:第一個參數不是方法信息。

選擇要調用的重載,然后提供這些類型的參數。

但坦率地說,我根本不明白為什么要這么做。 我看不到它打算代表原始lambda的哪一部分。 為什么行不只是listExpr1.Add(listContains); ???

就表達式樹而言, ids不是參數,因為它沒有傳遞給Func<...> 需要與之匹配的id的列表內置在表達式的結構中,因此Expression.Constant是處理它的正確方法。

但是,這還不是全部:因為ids是引用類型,所以只有對它的引用才會進入表達式的結構。 因此,如果您決定在構造表達式后更改列表的內容,則ids.Contains的含義將發生變化。

如果這不是您想要達到的效果,請復制列表:

Expression constIds = Expression.Constant(ids.ToList());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM