Как преобразовать результаты linq в HashSet или HashedSet

196

У меня есть свойство в классе, который является ISet. Я пытаюсь получить результаты запроса linq в это свойство, но не могу понять, как это сделать.

В основном, ищем последнюю часть этого:

ISet<T> foo = new HashedSet<T>();
foo = (from x in bar.Items select x).SOMETHING;

Может также сделать это:

HashSet<T> foo = new HashSet<T>();
foo = (from x in bar.Items select x).SOMETHING;
Джейми
источник
Я думаю, вы должны пропустить эту часть HashedSet. Это просто сбивает с толку, C#и LINQничего не называется HashedSet.
Jogge
Ответы идут в ящиках для ответов, а не в самом вопросе. Если вы хотите ответить на свой вопрос, который по правилам SO вполне подходит, пожалуйста, напишите ответ на этот вопрос.
Адриан

Ответы:

308

Я не думаю, что есть что-то встроенное, что делает это ... но действительно легко написать метод расширения:

public static class Extensions
{
    public static HashSet<T> ToHashSet<T>(
        this IEnumerable<T> source,
        IEqualityComparer<T> comparer = null)
    {
        return new HashSet<T>(source, comparer);
    }
}

Обратите внимание, что вам действительно нужен метод расширения (или, по крайней мере, универсальный метод некоторой формы) здесь, потому что вы не сможете явно выразить тип T:

var query = from i in Enumerable.Range(0, 10)
            select new { i, j = i + 1 };
var resultSet = query.ToHashSet();

Вы не можете сделать это с явным вызовом HashSet<T>конструктора. Мы полагаемся на вывод типов для универсальных методов, чтобы сделать это для нас.

Теперь вы можете назвать его ToSetи вернуться ISet<T>- но я бы придерживался ToHashSetи конкретного типа. Это согласуется со стандартными операторами LINQ ( ToDictionary, ToList) и учитывает расширение в будущем (например ToSortedSet). Вы также можете предоставить перегрузку, определяющую сравнение для использования.

Джон Скит
источник
2
Хороший вопрос по анонимным типам. Однако есть ли у анонимных типов полезные переопределения GetHashCodeи Equals? Если нет, они не будут очень хороши в HashSet ...
Джоэл Мюллер
4
@Joel: Да, они делают. В противном случае все виды вещей потерпят неудачу. По общему признанию они используют только сравнения по умолчанию для типов компонентов, но это обычно достаточно хорошо.
Джон Скит
2
@JonSkeet - знаете ли вы, есть ли причина, по которой это не предусмотрено в стандартных операторах LINQ наряду с ToDictionary и ToList? Я слышал, что часто бывают веские причины, по которым такие вещи опускаются, подобно отсутствующему методу IEnumerable <T> .ForEach
Стивен Холт,
1
@StephenHolt: Я согласен с сопротивлением ForEach, но ToHashSetимеет гораздо больше смысла - я не знаю ни одной причины, чтобы не делать ничего, ToHashSetкроме обычного «не соответствует плану полезности» (с которой я не согласен, но ...)
Джон Скит
1
@ Аарон: Не уверен ... возможно, потому что это было бы не так просто для поставщиков, не являющихся LINQ-to-Objects? (Я не могу представить, что это было бы невыполнимо, по общему признанию.)
Джон Скит