2011-02-02 17 views
17

Tôi đang sử dụng biểu thức lambda để sắp xếp và tìm kiếm một mảng trong C#. Tôi không muốn thực hiện giao diện IComparer trong lớp của mình, vì tôi cần sắp xếp và tìm kiếm trên nhiều trường thành viên.C# biểu thức lambda và IComparer

class Widget 
{ 
    public int foo; 

    public void Bar() 
    { 
     Widget[] widgets; 

     Array.Sort(widgets, (a, b) => a.foo.CompareTo(b.foo)); 

     Widget x = new Widget(); 
     x.foo = 5; 
     int index = Array.BinarySearch(widgets, x, 
             (a, b) => a.foo.CompareTo(b.foo)); 
    } 
} 

Trong khi các loại hoạt động tốt, việc tìm kiếm nhị phân đưa ra một lỗi biên dịch Không thể chuyển đổi biểu thức lambda để gõ 'System.Collections.IComparer <Widget>' vì nó không phải là một loại đại biểu. Vì một số lý do, sắp xếp có quá tải cho cả IComparer và So sánh, nhưng BinarySearch chỉ hỗ trợ IComparer. Sau khi một số nghiên cứu, tôi đã khám phá ra clunky ComparisonComparer<T> để chuyển đổi So sánh với một IComparer:

public class ComparisonComparer<T> : IComparer<T> 
{ 
    private readonly Comparison<T> comparison; 

    public ComparisonComparer(Comparison<T> comparison) 
    { 
     this.comparison = comparison; 
    } 

    int IComparer<T>.Compare(T x, T y) 
    { 
     return comparison(x, y); 
    } 
} 

Điều này cho phép tìm kiếm nhị phân để làm việc như sau:

int index = Array.BinarySearch(
    widgets, 
    x, 
    new ComparisonComparer<Widget>((a, b) => a.foo.CompareTo(b.foo))); 

Yuck. Có cách nào sạch hơn không?

+4

Các .NET4.5 sắp tới có một phương pháp 'Comparer <> Create' cho xây dựng một' IComparer <>. 'instance từ một đại biểu' IComparison <> '. –

Trả lời

9

Vâng, một tùy chọn là tạo một cái gì đó như ProjectionComparer thay thế. Tôi đã có một phiên bản đó trong MiscUtil - về cơ bản nó tạo ra một IComparer<T> từ một phép chiếu.

Vì vậy, ví dụ bạn sẽ là:

int index = Array.BinarySearch(widgets, x, 
           ProjectionComparer<Widget>.Create(x => x.foo)); 

Hoặc bạn có thể thực hiện phương pháp khuyến nông của riêng bạn trên T[] để làm cùng một loại điều:

public static int BinarySearchBy<TSource, TKey>(
    this TSource[] array, 
    TSource value, 
    Func<TSource, TKey> keySelector) 
{ 
    return Array.BinarySearch(array, value, 
           ProjectionComparer.Create(array, keySelector)); 
} 
+5

Đối với hồ sơ, ProjectionComparer , ValueComparer và CompareEx tất cả đều tốt. Vào cuối ngày, mặc dù, tôi tự hỏi tại sao một số phương pháp tích hợp chấp nhận So sánh và IComparer, và những người khác chỉ IComparer ... –

8

Bạn có thể sử dụng của tôi ValueComparer<T> class:

int index = Array.BinarySearch(
    widgets, x, 
    new ValueComparer<Widget>(x => x.Foo) 
); 

Bạn có thể so sánh theo nhiều thuộc tính bằng cách vượt qua nhiều biểu thức lambda.

3

Hãy thử điều này:

public static class ComparisonEx 
{ 
    public static IComparer<T> AsComparer<T>(this Comparison<T> @this) 
    { 
     if (@this == null) 
      throw new System.ArgumentNullException("Comparison<T> @this"); 
     return new ComparisonComparer<T>(@this); 
    } 

    public static IComparer<T> AsComparer<T>(this Func<T, T, int> @this) 
    { 
     if (@this == null) 
      throw new System.ArgumentNullException("Func<T, T, int> @this"); 
     return new ComparisonComparer<T>((x, y) => @this(x, y)); 
    } 

    private class ComparisonComparer<T> : IComparer<T> 
    { 
     public ComparisonComparer(Comparison<T> comparison) 
     { 
      if (comparison == null) 
       throw new System.ArgumentNullException("comparison"); 
      this.Comparison = comparison; 
     } 

     public int Compare(T x, T y) 
     { 
      return this.Comparison(x, y); 
     } 

     public Comparison<T> Comparison { get; private set; } 
    } 
} 

Nó cho phép bạn sử dụng đoạn mã này:

Comparison<int> c = (x, y) => x == y ? 0 : (x <= y ? -1 : 1); 
IComparer<int> icc = c.AsComparer(); 

Func<int, int, int> f = (x, y) => x == y ? 0 : (x <= y ? -1 : 1); 
IComparer<int> icf = f.AsComparer(); 
+1

ArgumentNullException mất một tên tham số, không có một loại. – SLaks

+0

Đây là những gì tôi cần. thanx – nima