Ответ 1
Предполагая, что вы имеете в виду LINQ to Objects, он в основном сохраняет набор всех результатов, которые он получил до сих пор, и возвращает только "текущий" элемент, если он раньше не был уступлен. Таким образом, результаты находятся в исходном порядке, при этом дубликаты удаляются. Что-то вроде этого (за исключением проверки ошибок и т.д.):
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source)
{
HashSet<T> set = new HashSet<T>();
foreach (T item in source)
{
if (set.Add(item))
{
// New item, so yield it
yield return item;
}
}
}
Это не гарантировано, но я не могу представить более разумную реализацию. Это позволяет Distinct()
быть таким же ленивым, как и может быть - данные возвращаются, как только это возможно, и буферизуется только минимальный объем данных.
Опираясь на это было бы плохой идеей, но может быть поучительно знать, как работает текущая реализация (по-видимому). В частности, вы можете легко заметить, что он начинает возвращать данные перед исчерпанием исходной последовательности, просто создавая источник, который регистрирует, когда он производит данные, которые будут потребляться Distinct
, а также регистрируется, когда вы получаете данные из Distinct
.