6

我有一个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 做到这一点,但不知道怎么做。我怎样才能做到这一点?

4

3 回答 3

6

假设你有一个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方法时,它将抛出 a ,因为没有字符串可以调用on。StringNullReferenceExceptionContains

where子句只是映射到上的Where扩展方法(确保有一个声明,以便编译器识别扩展方法)。Enumerableusing System.Linq;

如果您觉得 null 检查过多和/或重复,您可以像这样缩减代码:

// 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;

这稍微好一些,因为您正在封装冗余逻辑;如果逻辑发生变化,您只需在一处进行更改,它将应用于所有检查。如果需要,请随意用函数替换lambda 表达式。

如果要使用延迟执行query,则可以使用 a进行枚举。如果您需要在具体化列表中使用它(例如 a ),那么您只需调用类的扩展方法,如下所示:foreachList<User>ToListEnumerable

 IList<User> materializedResults = query.ToList();
于 2013-01-10T20:35:24.927 回答
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。例如

.WhereAtLeastOneProperty((string s) => s=="Tom")
于 2013-01-10T21:22:27.397 回答
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”。

于 2013-01-10T20:34:16.547 回答