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これらのフィールドのいずれかがnullの場合、のチェックは重要です。そうでない場合、クラスでContainsメソッドを呼び出すと、onを呼び出す文字列がないため、がスローされます。StringNullReferenceExceptionContains

whereは、クラスのWhere拡張メソッドにマップするだけです(拡張メソッドがコンパイラによって認識されるように、宣言があることを確認してください)。Enumerableusing 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;

冗長ロジックをカプセル化するので、これは少し優れています。ロジックが変更された場合は、1か所で変更するだけで、すべてのチェックに適用されます。必要に応じて、ラムダ式を関数に置き換えてください。

その後、遅延実行を使用する場合は、を使用queryして列挙できます。マテリアライズドリスト(のように)で必要な場合は、次のように、クラスの拡張メソッドを呼び出すだけです。foreachList<User>ToListEnumerable

 IList<User> materializedResults = query.ToList();
于 2013-01-10T20:35:24.927 に答える
3

きれいではありませんが、機能するはずです。

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

とはいえ、電話番号の中から「トム」という文字列を検索する必要がある理由がわかりません。

于 2013-01-10T20:34:16.547 に答える
3

静的クラスの1つのジェネリック拡張メソッドをコピーします。

    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();

または、他のラムダを使用して、ニーズをより適切に満たすことができます。例えば

.WhereAtLeastOneProperty((string s) => s=="Tom")
于 2013-01-10T21:22:27.397 に答える