Noto uno strano comportamento nel metodo Sort() della lista generica List<T>.

Preambolo. Avete una classe del tipo:

class Tupla
{
    public Int32 Value { get; set; }
    public String Description { get; set; }
}

ne avete n istanze in una lista e volete ordinare la lista in base al valore della proprietà Value, per farlo è necessario utilizzare un IComparer<T> custom, una cosa del tipo:

class TuplaComparer : IComparer<Tupla>
{
    public int Compare( Tupla x, Tupla y )
    {
        return x.Value.CompareTo( y.Value );
    }
}

peccaco che succedano un po’ di cose curiose :-D, questo test fallisce miseramente:

[TestMethod]
public void tuplaComparer_using_listOfT_sort_should_sort_as_expected()
{
    var list = new List<Tupla>()
    {
        new Tupla() { Value = 0, Description = "B" },
        new Tupla() { Value = 0, Description = "A" }
    };

    list.Sort( new TuplaComparer() );

    Assert.AreEqual<String>( "B", list[ 0 ].Description );
    Assert.AreEqual<String>( "A", list[ 1 ].Description );
}

il metodo Sort() cioè swappa gli elementi uguali, ma secondo me non è il comportamento corretto, se sono uguali, e lo dice il  vostro IComparer<T> perchè ritorna 0, devono restare al loro posto e non essere spostati.

Utilizzando infatti un altro meccanismo di sort il comportamento è quello atteso:

[TestMethod]
public void tuplaComparer_using_linq_sort_should_sort_as_expected()
{
    var list = new List<Tupla>()
    {
        new Tupla() { Value = 0, Description = "B" },
        new Tupla() { Value = 0, Description = "A" }
    };

    var actual = list.OrderBy( t => t, new TuplaComparer() );

    Assert.AreEqual<String>( "B", actual.ElementAt( 0 ).Description );
    Assert.AreEqual<String>( "A", actual.ElementAt( 1 ).Description );
}

In questo caso, utilizzando lo stesso IComparer<T>, ma passando dalla OrderBy<T> di Linq to Objects la cosa funziona come mi aspetto e infatti il test passa.

A casa mia si chiama bug, che ne pensate?

Update:

Non è un bug ma un comportamento documentato: http://msdn.microsoft.com/en-us/library/234b841s.aspx

Si chiama “Unstable Sort” e non garantisce l’ordine degli elementi in caso di uguaglianza, esattamente il mio caso, mentre la OrderBy<T>() invece implementa uno “Stable Sort” garantendo l’ordine degli elementi in caso di uguaglianza.

Grazie a Luka per la segnalazione.

.m