linq-Distinct


源码:

        public static IEnumerable Distinct(this IEnumerable source) {
            if (source == null) throw Error.ArgumentNull("source");
            return DistinctIterator(source, null);
        }
 
        public static IEnumerable Distinct(this IEnumerable source, IEqualityComparer comparer) {
            if (source == null) throw Error.ArgumentNull("source");
            return DistinctIterator(source, comparer);
        }
 
        static IEnumerable DistinctIterator(IEnumerable source, IEqualityComparer comparer) {
            Set set = new Set(comparer);
            foreach (TSource element in source)
                if (set.Add(element)) yield return element;
        }

看下Set类的实现:

    internal class Set
    {
        int[] buckets;
        Slot[] slots;
        int count;
        int freeList;
        IEqualityComparer comparer;
 
        public Set() : this(null) { }
 
        public Set(IEqualityComparer comparer) {
            if (comparer == null) comparer = EqualityComparer.Default;
            this.comparer = comparer;
            buckets = new int[7];
            slots = new Slot[7];
            freeList = -1;
        }
 
        // If value is not in set, add it and return true; otherwise return false
        public bool Add(TElement value) {
            return !Find(value, true);
        }
 
        // Check whether value is in set
        public bool Contains(TElement value) {
            return Find(value, false);
        }
 
        // If value is in set, remove it and return true; otherwise return false
        public bool Remove(TElement value) {
            int hashCode = InternalGetHashCode(value);
            int bucket = hashCode % buckets.Length;
            int last = -1;
            for (int i = buckets[bucket] - 1; i >= 0; last = i, i = slots[i].next) {
                if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value)) {
                    if (last < 0) {
                        buckets[bucket] = slots[i].next + 1;
                    }
                    else {
                        slots[last].next = slots[i].next;
                    }
                    slots[i].hashCode = -1;
                    slots[i].value = default(TElement);
                    slots[i].next = freeList;
                    freeList = i;
                    return true;
                }
            }
            return false;
        }
 
        bool Find(TElement value, bool add) {
            int hashCode = InternalGetHashCode(value);
            for (int i = buckets[hashCode % buckets.Length] - 1; i >= 0; i = slots[i].next) {
                if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value)) return true;
            }
            if (add) {
                int index;
                if (freeList >= 0) {
                    index = freeList;
                    freeList = slots[index].next;
                }
                else {
                    if (count == slots.Length) Resize();
                    index = count;
                    count++;
                }
                int bucket = hashCode % buckets.Length;
                slots[index].hashCode = hashCode;
                slots[index].value = value;
                slots[index].next = buckets[bucket] - 1;
                buckets[bucket] = index + 1;
            }
            return false;
        }
 
        void Resize() {
            int newSize = checked(count * 2 + 1);
            int[] newBuckets = new int[newSize];
            Slot[] newSlots = new Slot[newSize];
            Array.Copy(slots, 0, newSlots, 0, count);
            for (int i = 0; i < count; i++) {
                int bucket = newSlots[i].hashCode % newSize;
                newSlots[i].next = newBuckets[bucket] - 1;
                newBuckets[bucket] = i + 1;
            }
            buckets = newBuckets;
            slots = newSlots;
        }
 
        internal int InternalGetHashCode(TElement value)
        {
            //Microsoft DevDivBugs 171937. work around comparer implementations that throw when passed null
            return (value == null) ? 0 : comparer.GetHashCode(value) & 0x7FFFFFFF;
        }
 
        internal struct Slot
        {
            internal int hashCode;
            internal TElement value;
            internal int next;
        }
    }

这样还是比较清楚的。