2011-02-02 10 views
17

मैं सी # में सरणी को सॉर्ट और खोजने के लिए लैम्ब्डा एक्सप्रेशन का उपयोग कर रहा हूं। मैं अपनी कक्षा में आईसीओएमपेयर इंटरफेस को लागू नहीं करना चाहता, क्योंकि मुझे कई सदस्य फ़ील्ड को सॉर्ट और खोजना होगा।सी # लैम्ब्डा एक्सप्रेशन और आईसीओएमपेयर

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)); 
    } 
} 

तरह ठीक काम करता है, वहीं द्विआधारी खोज एक संकलन त्रुटि टाइप करने के लिए 'System.Collections.IComparer < विजेट >' क्योंकि यह एक प्रतिनिधि प्रकार नहीं है लैम्ब्डा अभिव्यक्ति कनवर्ट नहीं कर सकता देता है। किसी कारण से, सॉर्ट में आईसीओम्पियर और तुलना दोनों के लिए अधिभार है, लेकिन बाइनरीशर्च केवल आईसीओएमपेयर का समर्थन करता है। कुछ शोध के बाद, मैं एक IComparer से तुलना कन्वर्ट करने के लिए भद्दा ComparisonComparer<T> की खोज:

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); 
    } 
} 

यह अनुमति देता है द्विआधारी खोज के रूप में निम्नानुसार काम करने के लिए:

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

नीरस। क्या कोई क्लीनर तरीका है?

+4

आगामी .NET4.5 एक विधि 'comparer <> एक' IComparer के निर्माण के लिए Create' <> है '' IComparison <> 'प्रतिनिधि से उदाहरण। –

उत्तर

9

ठीक है, एक विकल्प ProjectionComparer जैसे कुछ बनाने के लिए है। मेरे पास MiscUtil में इसका एक संस्करण मिला है - यह मूल रूप से प्रक्षेपण से IComparer<T> बनाता है।

तो अपने उदाहरण होगा:

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

या आप बात का एक ही प्रकार का क्या करना T[] पर अपने खुद के विस्तार के तरीकों को लागू कर सकते हैं:

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

रिकॉर्ड के लिए, प्रक्षेपणकंपर , ValueComparer , और तुलना सभी ठीक दिखते हैं। दिन के अंत में, मुझे आश्चर्य है कि क्यों कुछ अंतर्निहित तरीकों तुलना और आईकॉम्पियर स्वीकार करते हैं, और अन्य सिर्फ आईसीओएमपेयर ... –

8

आप उपयोग कर सकते हैं मेरी ValueComparer<T> class:

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

आप गुजरने से कई गुणों की तुलना कर सकते हैं एकाधिक लैम्ब्डा अभिव्यक्तियां।

3

इस प्रयास करें:

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; } 
    } 
} 

यह आप इस कोड का उपयोग करने देता है:।

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 एक प्रकार के बिना पैरामीटर नाम लेता है। – SLaks

+0

यही मुझे चाहिए। thanx – nima

संबंधित मुद्दे