Почему я не могу использовать это вложенное лямбда-выражение? - PullRequest
3 голосов
/ 21 октября 2011

Я пытаюсь вести список уникальных моделей из множества запросов. К сожалению, метод equals наших моделей не определен, поэтому я не мог легко использовать хеш-карту.

В качестве быстрого исправления я использовал следующий код:

public void AddUnique(
    List<Model> source,
    List<Model> result)
{
    if (result != null)
    {
        if (result.Count > 0
            && source != null
            && source.Count > 0)
        {
            source.RemoveAll(
                s => result.Contains(
                    r => r.ID == s.ID));
        }

        result.AddRange(source);
    }
}

К сожалению, это не работает. Проходя через код, я обнаружил, что, хотя я проверил, чтобы был хотя бы один Model с одинаковыми ID в source и result, строка RemoveAll(Predicate<Model>) делает Не изменять количество элементов в source. Чего мне не хватает?

Ответы [ 4 ]

10 голосов
/ 21 октября 2011

Приведенный выше код даже не должен компилироваться, поскольку Contains ожидает Model, а не предикат.

Вы можете использовать Any () вместо:

source.RemoveAll(s => result.Any(r => r.ID == s.ID));

Это удалит предметы из источника правильно.

1 голос
/ 21 октября 2011

Я мог бы решить проблему другим способом.

Вы сказали, что у вас нет подходящих реализаций равенства внутри класса. Может быть, вы не можете изменить это. Однако вы можете определить реализацию IEqualityComparer<Model>, которая позволяет вам указать соответствующие реализации Equals и GetHashCode, внешние по отношению к самому фактическому классу Model.

var comparer = new ModelComparer();
var addableModels = newSourceOfModels.Except(modelsThatAlreadyExist, comparer);
// you can then add the result to the existing

Где вы можете определить компаратор как

class ModelComparer : IEqualityComparer<Model>
{
     public bool Equals(Model x, Model y)
     {
         // validations omitted
         return x.ID == y.ID;
     }

     public int GetHashCode(Model m)
     {
         return m.ID.GetHashCode();
     }
}
0 голосов
/ 21 октября 2011

Ваш код удаляет все модели, которые одинаковы между двумя списками, а не те, которые имеют одинаковые ID .Если они на самом деле не являются одинаковыми экземплярами модели, она не будет работать так, как вы ожидаете.

Иногда я использую эти методы расширения для такого рода вещей:

public static class CollectionHelper
{
    public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> selector)
    {
        var itemsToRemove = list.Where(selector).ToList();
        foreach (var item in itemsToRemove)
        {
            list.Remove(item);
        }
    }

    public static void RemoveWhere<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<KeyValuePair<TKey, TValue>, bool> selector)
    {
        var itemsToRemove = dictionary.Where(selector).ToList();
        foreach (var item in itemsToRemove)
        {
            dictionary.Remove(item);
        }
    }
}
0 голосов
/ 21 октября 2011
source.RemoveAll(source.Where(result.Select(r => r.ID).Contains(source.Select(s => s.ID))));

Цель этого утверждения - создать два перечисления идентификаторов: один для источника и один для результата. Затем он вернет true для оператора where для каждого из элементов в обоих перечислениях. Затем он удалит все элементы, которые возвращают true.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...