2017-02-08 39 views
1

我想建立一個像動態下面的表達式。建立一個動態表達式與嵌套或之間的許多ANDS

SomeList.Where(person => person.firstname == "foo" && 
       (person.lastanme == "bar" ||person.middleName == "bar") && 
       person.age == 65) 

我使用了一個名爲PredicateBuilder類:

public static class PredicateBuilder 
{ 
    public static Expression<Func<T, bool>> True<T>() { return f => true; } 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 

    public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
      (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
      (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters); 
    } 
} 

我第一次驗證,如果一個搜索對象的特性被填寫,如果他們那麼我將其稱爲構建基於謂詞的方法該財產。然後我將所有這些添加到謂詞列表中。最後,我用PredicateBuilder.And()方法遍歷列表中的所有謂詞。

但是,我需要能夠過濾兩個不同的屬性,如姓或中間名。

我想要一個如何動態構建這些謂詞並在需要時插入它們之間的示例,或者提供更好的總體設計以滿足我的需求的示例。

在下面的代碼中我調用CreatePredicate()。

private static List<Expression<Func<DirectoryEntry,bool>>> _conditionsList = new List<Expression<Func<DirectoryEntry,bool>>>(); 
    public static Expression<Func<DirectoryEntry, bool>> CreatePredicate(DirectorySearchData searchData) 
    { 
     _conditionsList.Clear(); 

     var predicate = PredicateBuilder.False<DirectoryEntry>(); 

     AddFirstNameCondition(searchData); 
     AddLastNameCondition(searchData); 
     AddUsernameCondition(searchData); 

     predicate = BuilPredicateFromConditionList(predicate); 

     return predicate; 
    } 

private static void AddFirstNameCondition(DirectorySearchData searchData) 
    { 
     if (!String.IsNullOrWhiteSpace(searchData.FirstName)) 
     { 
      _conditionsList.Add(entry => entry.FirstName.ToLower().Contains(searchData.FirstName.ToLower())); 
     } 
    } 

    private static void AddLastNameCondition(DirectorySearchData searchData) 
    { 
     if (!String.IsNullOrWhiteSpace(searchData.LastName)) 
     { 
      _conditionsList.Add(entry => entry.LastName.ToLower().Contains(searchData.LastName.ToLower())); 
     } 
    } 

    private static void AddUsernameCondition(DirectorySearchData searchData) 
    { 
     if (!String.IsNullOrWhiteSpace(searchData.UserName)) 
     { 
      _conditionsList.Add(entry => entry.Username.ToLower().Contains(searchData.UserName.ToLower())); 
     } 
    } 

private static Expression<Func<DirectoryEntry, bool>> BuilPredicateFromConditionList(Expression<Func<DirectoryEntry, bool>> predicate) 
    { 
     if (_conditionsList == null || _conditionsList.Count <= 0) return predicate; 

     predicate = PredicateBuilder.True<DirectoryEntry>(); 
     foreach (var condition in _conditionsList) 
     { 
      predicate = PredicateBuilder.And(predicate, condition); 
     } 
     return predicate; 
    } 

    public class DirectorySearchData 
{ 

    public string LastName { get; set; } 
    public string FirstName { get; set; } 
    public string UserName { get; set; } 
    public string CampusPhone { get; set; } 
    public string CampusAddress { get; set; } 
    public string CampusBox { get; set; } 
    public string HomeAddress { get; set; } 
    public string HomeState { get; set; } 
    public string DepartmentOrOffice { get; set; } 
    public string StudentMajor { get; set; } 
    public string Concentration { get; set; } 
    public string SgaCabinetPositionName { get; set; } 
    public string Hiatus { get; set; } 
    public string StudentClass { get; set; } 

    public DirectorySearchData() 
    { 
     LastName = ""; 
     FirstName = ""; 
     UserName = ""; 
     CampusPhone = ""; 
     CampusAddress = ""; 
     CampusBox = ""; 
     HomeAddress = ""; 
     HomeState = ""; 
     DepartmentOrOffice = ""; 
     StudentMajor = ""; 
     Concentration = ""; 
     SgaCabinetPositionName = ""; 
     Hiatus = ""; 
     StudentClass = ""; 
    } 
} 

}

+0

'person.firstname = 「富」'或'person.firstname = =「foo」'?首先在構建動態表達式之前糾正你的靜態代碼;) – grek40

+0

HAHA謝謝,我只是打字太快:) – Mike

+0

請注意=>是lambda操作符!您的「示例」包含四個(因此沒有意義),但只有一個是必要的,如下所示: (p =>(pa || pb)&& pc) – user1890202

回答

0

爲了創造更多的複雜表情,你可以在Add*Condition方法使用更復雜的表達。針對你的情況構建OR表達您可以使用下一個方法:

private static void AddLastNameOrMiddleNameCondition(DirectorySearchData searchData) 
{ 
    if (!string.IsNullOrWhiteSpace(searchData.LastName)) 
    { 
    var lastNameOrMiddleName = PredicateBuilder.Or(
     (DirectorySearchData entry) => entry.LastName.ToLower().Contains(searchData.LastName.ToLower()), 
     (DirectorySearchData entry) => entry.MiddleName.ToLower().Contains(searchData.MiddleName.ToLower())); 

    _conditionsList.Add(lastNameOrMiddleName); 
    } 
} 

UPD:以上сleaner例如:

private static void AddLastNameOrMiddleNameCondition(DirectorySearchData searchData) 
{ 
    if (!string.IsNullOrWhiteSpace(searchData.LastName)) 
    { 
    var inner = PredicateBuilder.New<DirectorySearchData>(false); 
    // BTW, Use New<T> insted of PredicateBuilder.False<DirectorySearchData>(); methods False<T> and True<T> are obsolete. 
    inner = inner.Or(entry => entry.LastName.ToLower().Contains(searchData.LastName.ToLower())); 
    inner = inner.Or(entry => entry.MiddleName.ToLower().Contains(searchData.MiddleName.ToLower())); 

    _conditionsList.Add(inner); 
    } 
} 
+0

PredicateBuilder類的引用與上面提到的相同嗎?還是來自其他源? – Mike

+0

@Mike,從你的來源,我使用LinqKik 1.1.8.0版本。不包括1.1.7.1以下的版本,不包括'New'和'New '方法,在這個版本中只使用'PredicateBuilder.False ()'。 –

+1

非常感謝,你的回答幫助我找出我失蹤的東西!我很明白新構建lambda表達式,所以我非常感謝您的時間和幫助! – Mike

相關問題