18
 class p {
     public string Name { get; set; }
     public int Age { get; set; }
 };

 static List<p> ll = new List<p>
 {
     new p{Name="Jabc",Age=53},new p{Name="Mdef",Age=20},
     new p{Name="Exab",Age=45},new p{Name="G123",Age=19}
 };
 protected static void SortList()
 {
     IComparer<p> mycomp = (x, y) => x.Name.CompareTo(y.Name);  <==(Line 1)
     ll.Sort((x, y) => x.Name.CompareTo(y.Name));<==(Line 2)
 }

Here the List.sort expects an IComparer<p> as parameter. And it works with the lambda as shown in Line 2. But when I try to do as in Line 1, I get this error:

Cannot convert lambda expression to type System.Collections.Generic.IComparer' because it is not a delegate type

I investigated this for quite some time but I still don't understand it.Maybe my understanding of IComparer is not quite good.Can somebody give me a hand ?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
josephj1989
  • 9,509
  • 9
  • 48
  • 70

4 Answers4

23

When you do ll.Sort((x, y) => x.Name.CompareTo(y.Name)); it uses the overload for Comparison<T>, not IComparer. Comparison<T> is a delegate, so you can use a lambda expression for it.

Comparison<p> mycomp = (x, y) => x.Name.CompareTo(y.Name); will work.

BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283
sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • Where/how is Comparison defined? – Doguhan Uluca Apr 04 '12 at 20:53
  • 2
    @duluca It's defined in the `System` namespace as `public delegate int Comparison(T x, T y)` (minus the `in` in versions prior to .net 4). It's documented [here](http://msdn.microsoft.com/en-us/library/tfakywbh%28v=vs.100%29.aspx). – sepp2k Apr 04 '12 at 21:02
  • `CompareTo()` is a culture specific comparison. Something like `ll.sort((x, y) => String.CompareOrdinal(x.Name, y.Name))` may suit you better. – Ryan Kirkman Mar 04 '13 at 00:03
  • I like how I could lift the *exact* mycomp definition here to work in my scenario :) – nchaud Oct 22 '14 at 11:52
  • 1
    @RyanKirkman How often do you want to compare two `Name`s according to the numeric value of the underlying UTF-16 code units? Normally, when you sort "names" you use an alphabet relevant in the context, and that is indeed culture-specific. – Jeppe Stig Nielsen Aug 18 '17 at 17:17
9

There's an existing solution you might refer to: https://stackoverflow.com/a/16839559/371531

This one uses Comparer<T>.Create introduced in .NET Framework 4.5.

Community
  • 1
  • 1
Liu Yue
  • 382
  • 5
  • 6
2

IComparer is an interface, not a delegate.

You'll want to use the lambda expression on its .CompareTo(), not on the interface itself.

devoured elysium
  • 101,373
  • 131
  • 340
  • 557
1

Use the following simple class:

public static class ComparerUtilities
{
    class _Comparer<T> : Comparer<T>
    {
        Comparison<T> _comparison;

        public _Comparer(Comparison<T> comparison)
        {
            _comparison = comparison;
        }

        public override int Compare(T x, T y)
        {
            return _comparison(x, y);
        }
    }

    public static IComparer<T> FromComparison<T>(Comparison<T> comparison)
    {
        return new _Comparer<T>(comparison);
    }
}
ezolotko
  • 1,723
  • 1
  • 21
  • 21