搜索任何和所有匹配的对象列表

时间:2013-01-10 20:32:40

标签: c# .net linq

我有List<T>User个实例,我需要搜索User中的所有字段。

最有效的方法是什么?

这是我的User类的定义:

public class User
{
    public String SamAccountName { get; set; }
    public String EmailAddress { get; set; }
    public String WorkPhone { get; set; }
    public String MobilePhone { get; set; }
    public String Office { get; set; }
}

我需要搜索以查看“Tom”的值是否包含在任何字段的任何字符串中,并返回一个只有符合该条件的实例的新List<T>

我想用LINQ做这个,但不知道怎么做。我怎么能这样做?

3 个答案:

答案 0 :(得分:5)

假设你有一个IEnumerable<User>,你可以这样做:

// Query for "Tom" being contained in any of the fields.
var query =
    from user in users
    where
        (user.SamAccountName != null && user.SamAccountName.Contains("Tom")) ||
        (user.EmailAddress != null && user.EmailAddress.Contains("Tom")) ||
        (user.WorkPhone != null && user.WorkPhone.Contains("Tom")) ||
        (user.MobilePhone != null && user.MobilePhone.Contains("Tom")) ||
        (user.Office != null && user.Office.Contains("Tom"))
    select user;

注意,如果任何这些字段为空,则null的检查很重要,否则,当您在Contains method上调用String class时,它会抛出{{} 3}}因为没有字符串可以调用Contains

NullReferenceException只是映射到where clause上的Where extension method(请确保有using System.Linq;声明,以便编译器识别扩展方法。)

如果您认为空检查过多和/或重复,您可以像这样减少代码:

// Generate your predicate.
Func<string, bool> checkContainsTom = s => s != null && s.Contains("Tom");

// Query.
var query =
    from user in users
    where
        checkContainsTom(user.SamAccountName) ||
        checkContainsTom(user.EmailAddress) ||
        checkContainsTom(user.WorkPhone) ||
        checkContainsTom(user.MobilePhone) ||
        checkContainsTom(user.Office)
    select user;

这稍微好一些,因为你正在封装冗余逻辑;如果逻辑发生变化,您只需在一个地方更改它,它就会应用于所有检查。如果需要,可以随意使用函数替换Enumerable class

如果您想使用lambda expression,则可以使用foreach通过query进行枚举。如果您在实体列表中需要它(例如deferred execution),那么您只需调用Enumerable类上的List<User>,就像这样:

 IList<User> materializedResults = query.ToList();

答案 1 :(得分:3)

它不漂亮,但应该有效:

users.Where(u => u.SamAccountName.Contains("Tom") ||
                 u.EmaildAddress.Contains("Tom") ||
                 u.WorkPhone.Contains("Tom") ||
                 u.MobilePhone.Contains("Tom") ||
                 u.Office.Contains("Tom"));

虽然,我不得不说,我不明白为什么你需要在电话号码里搜索字符串“Tom”。

答案 2 :(得分:3)

在一些静态类中复制一个通用扩展方法:

    public static IEnumerable<T> WhereAtLeastOneProperty<T, PropertyType>(this IEnumerable<T> source, Predicate<PropertyType> predicate)
    {            
        var properties = typeof(T).GetProperties().Where(prop => prop.CanRead && prop.PropertyType == typeof(PropertyType)).ToArray();
        return source.Where(item => properties.Any(prop => PropertySatisfiesPredicate(predicate, item, prop)));
    }

    private static bool PropertySatisfiesPredicate<T, PropertyType>(Predicate<PropertyType> predicate, T item, System.Reflection.PropertyInfo prop)
    {
        try
        {
            return predicate((PropertyType)prop.GetValue(item));
        }
        catch
        {
            return false;
        }
    }

然后你打电话:

var usersList = new List<User>();
var filteredUsersList = usersList.WhereAtLeastOneProperty((string s) => s.Contains("Tom")).ToList();

或者使用其他一些lambda来更好地满足您的需求。 e.g。

.WhereAtLeastOneProperty((string s) => s=="Tom")