Dans le .NET Framework 3.5, en désassemblant le CIL de l'implémentation Linq-to-Objects de Distinct()
, on constate que l'ordre des éléments est préservé - cependant, ce comportement n'est pas documenté.
J'ai mené une petite investigation avec Reflector. Après avoir désassemblé System.Core.dll, Version=3.5.0.0, on peut voir que Distinct() est une méthode d'extension, qui ressemble à ceci :
public static class Emunmerable
{
public static IEnumerable Distinct(this IEnumerable source)
{
if (source == null)
throw new ArgumentNullException("source");
return DistinctIterator(source, null);
}
}
Donc, ce qui est intéressant ici, c'est DistinctIterator, qui implémente IEnumerable et IEnumerator. Voici une implementation simplifiée (avec les goto et les labels supprimés) de cet IEnumerator :
private sealed class DistinctIterator : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable
{
private bool _enumeratingStarted;
private IEnumerator _sourceListEnumerator;
public IEnumerable _source;
private HashSet _hashSet;
private TSource _current;
private bool MoveNext()
{
if (!_enumeratingStarted)
{
_sourceListEnumerator = _source.GetEnumerator();
_hashSet = new HashSet();
_enumeratingStarted = true;
}
while(_sourceListEnumerator.MoveNext())
{
TSource element = _sourceListEnumerator.Current;
if (!_hashSet.Add(element))
continue;
_current = element;
return true;
}
return false;
}
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
TSource IEnumerator.Current
{
get { return _current; }
}
object IEnumerator.Current
{
get { return _current; }
}
}
Comme vous pouvez le voir - l'énumération se fait dans l'ordre fourni par l'énumérable source (list, sur laquelle nous appelons Distinct
). HashSet
est utilisé uniquement pour déterminer si nous avons déjà retourné un tel élément ou non. Si ce n'est pas le cas, nous le retournons, sinon - nous continuons l'énumération sur la source.
Il est donc garanti que Distinct()
retournera les éléments exactement dans le même ordre, qui ont été fournis par la collection sur laquelle Distinct a été appliqué.