Sorting an IList in C#

前端 未结 15 2381
臣服心动
臣服心动 2020-11-28 06:36

So I came across an interesting problem today. We have a WCF web service that returns an IList. Not really a big deal until I wanted to sort it.

Turns out the IList

15条回答
  •  我在风中等你
    2020-11-28 06:52

    The accepted answer by @DavidMills is quite good, but I think it can be improved upon. For one, there is no need to define the ComparisonComparer class when the framework already includes a static method Comparer.Create(Comparison). This method can be used to create an IComparison on the fly.

    Also, it casts IList to IList which has the potential to be dangerous. In most cases that I have seen, List which implements IList is used behind the scenes to implement IList, but this is not guaranteed and can lead to brittle code.

    Lastly, the overloaded List.Sort() method has 4 signatures and only 2 of them are implemented.

    1. List.Sort()
    2. List.Sort(Comparison)
    3. List.Sort(IComparer)
    4. List.Sort(Int32, Int32, IComparer)

    The below class implements all 4 List.Sort() signatures for the IList interface:

    using System;
    using System.Collections.Generic;
    
    public static class IListExtensions
    {
        public static void Sort(this IList list)
        {
            if (list is List)
            {
                ((List)list).Sort();
            }
            else
            {
                List copy = new List(list);
                copy.Sort();
                Copy(copy, 0, list, 0, list.Count);
            }
        }
    
        public static void Sort(this IList list, Comparison comparison)
        {
            if (list is List)
            {
                ((List)list).Sort(comparison);
            }
            else
            {
                List copy = new List(list);
                copy.Sort(comparison);
                Copy(copy, 0, list, 0, list.Count);
            }
        }
    
        public static void Sort(this IList list, IComparer comparer)
        {
            if (list is List)
            {
                ((List)list).Sort(comparer);
            }
            else
            {
                List copy = new List(list);
                copy.Sort(comparer);
                Copy(copy, 0, list, 0, list.Count);
            }
        }
    
        public static void Sort(this IList list, int index, int count,
            IComparer comparer)
        {
            if (list is List)
            {
                ((List)list).Sort(index, count, comparer);
            }
            else
            {
                List range = new List(count);
                for (int i = 0; i < count; i++)
                {
                    range.Add(list[index + i]);
                }
                range.Sort(comparer);
                Copy(range, 0, list, index, count);
            }
        }
    
        private static void Copy(IList sourceList, int sourceIndex,
            IList destinationList, int destinationIndex, int count)
        {
            for (int i = 0; i < count; i++)
            {
                destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
            }
        }
    }
    

    Usage:

    class Foo
    {
        public int Bar;
    
        public Foo(int bar) { this.Bar = bar; }
    }
    
    void TestSort()
    {
        IList ints = new List() { 1, 4, 5, 3, 2 };
        IList foos = new List()
        {
            new Foo(1),
            new Foo(4),
            new Foo(5),
            new Foo(3),
            new Foo(2),
        };
    
        ints.Sort();
        foos.Sort((x, y) => Comparer.Default.Compare(x.Bar, y.Bar));
    }
    

    The idea here is to leverage the functionality of the underlying List to handle sorting whenever possible. Again, most IList implementations that I have seen use this. In the case when the underlying collection is a different type, fallback to creating a new instance of List with elements from the input list, use it to do the sorting, then copy the results back to the input list. This will work even if the input list does not implement the IList interface.

提交回复
热议问题