Картинка блога

Часто возникает потребность отфильтровать одинаковые элементы в списке. В LINQ есть метод Distinct, который получает интерфейс IEqualityComparer. Не совсем понятно, почему метод не может получать lamda-выражение. Следующий код должен исправить положение:

class EqualityComparer : IEqualityComparer
{
    public Func DistinctDelegate;

    public bool Equals(T x, T y)
    {
        return DistinctDelegate(x).ToString() == DistinctDelegate(y).ToString();
    }
    public int GetHashCode(T obj)
    {
        return obj.ToString().ToLower().GetHashCode();
    }
}

public static IEnumerable Distinct(this IEnumerable coll, Func distinctDelegate)
{
    EqualityComparer myd = new EqualityComparer();
    myd.DistinctDelegate = distinctDelegate;
    return coll.Distinct(myd);
}

public static IQueryable Distinct(this IQueryable coll, Func distinctDelegate)
{
    EqualityComparer myd = new EqualityComparer();
    myd.DistinctDelegate = distinctDelegate;
    return coll.Distinct(myd);
}

Первый метод используется для Linq2Object, второй — Linq2SQL.

Использование:

var words = from x in new[] { "dog", "cat", "cat" } select new { Word = x };
var distinctWords = words.Distinct(x => x.Word);

Код предоставил Владимир Калошин.

Метки:,

3 комментария в “Фильтр одинаковых объектов в LINQ.”

  1. Добрый день,

    Вопрос, косвенно связанный с постом, но напрямую — с блогом 🙂

    Если сформулировать вкратце, то как сделать ObjectTrackingEnabled=false и SubmitChanges одновременно?
    Т.е. если я извлекаю какие-то данные конструкцией select c, затем в другом приложении меняю эти данные, и читаю в исходном снова — они не меняются, LINQ соханяет их в текущий кэш.
    Refresh объекта делать не всегда возможно (например, я удалил запись). Создавать каждый раз новый контекст — забить память (dispose не приводит к немедленному освобождению памяти).

    А как Вы строите многопользовательские приложения?

  2. Здравствуйте Роман.

    Начну снизу. Обычно, в многопользовательских приложениях я разделаю уровень данных и интерфейс каналом WCF.
    Если задание требует .NET2.0 использую NHiretnate. Я не слышал в LINQ2SQL об использовании кеша, в NHibernate например из 2 и настраиваются они
    на уровне SesssionFactory. Когда только начинал использовать LINQ, DataContext выдавал массу ошибок при использовании его как синглтон.
    Сейчас создаю новый DataContext для каждой задачи, плюс транзакции. В обоих случаях LINQ2SQL или NHibernate, для обновления данных в базе,
    нужно вызвать соответствующие методы.

    Добрый коллега, некоторое время назад, вел дискуссию с господином Альбахари (http://www.albahari.com/), оба согласились с тем, что Linq2SQL и также
    EntityFramwork имеют «недоработки» именно с ObjectTrackingEnabled и SubmitChanges. Небольшой пример и описание проблемы по моему было здесь (/791-linq-ins.....o-reshenie)

    Надеюсь я смог ответить на ваш вопрос 🙂

  3. Продолжу традицию «Снизу» 🙂
    Метод InsertOrUpdateOnSubmit не работает если данные обновлены в другой копии приложения, нужна скорее перегрузка методов select.
    Создавать отдельный DataContext — собственно так и поступаю, но не могу освободить от него память, Dispose, приравнивание в null и сборка мусора не помогают, поэтому память в процессе работы только растет.
    NHibernate наверное несколько поздновато т.к. довольно объемное приложение реализовано на LINQ2SQL.
    А что за методы используете для обновления данных? Как понимаю это врядли Refresh, т.к. он работает только для конкретных объектов.