47

मैंने कुछ कोड देखा है जहां इस लड़के ने एक ArrayList.Sort (IComparer यहां) या एक IENumerable.SequenceEqual (IENumerable सूची, IEqualityComparer) पर लैम्ब्डा अभिव्यक्ति पारित की है, जहां एक आईसीओएमपेयर या आईक्वालिटी कॉम्पैयर की अपेक्षा की गई थी।आईसीओएमपेयर या आईक्वालिटी कॉम्पैयर या किसी एकल-विधि इंटरफ़ेस के स्थान पर लैम्ब्डा अभिव्यक्ति पास करें?

मुझे यकीन नहीं है कि मैंने इसे देखा है, या मैं बस सपना देख रहा हूं। और मुझे इनमें से किसी भी संग्रह पर कोई एक्सटेंशन नहीं दिख रहा है जो एक Func <> या उनके विधि हस्ताक्षर में एक प्रतिनिधि स्वीकार करता है।

क्या ऐसी अधिभार/विस्तार विधि है? या, यदि नहीं, तो क्या इस तरह के आसपास मक करना संभव है और एक एल्गोरिदम पास करें (प्रतिनिधि को पढ़ें) जहां एकल-विधि इंटरफ़ेस की अपेक्षा की जाती है?

अद्यतन धन्यवाद, हर कोई। बिल्कुल यही मैने सोचा। मुझे सपना देखना होगा। मुझे पता है कि रूपांतरण कैसे लिखना है। मुझे यकीन नहीं था कि अगर मैंने ऐसा कुछ देखा होगा या सिर्फ सोचा था कि मैंने इसे देखा होगा।

फिर भी एक और अपडेट देखो, यहां, मुझे ऐसा एक उदाहरण मिला। मैं सब के बाद सपना देख रहा था। what this guy is doing here पर देखें। क्या देता है?

और यहां एक और अपडेट है: ठीक है, मुझे मिल गया। लड़का Comparison<T> अधिभार का उपयोग कर रहा है। अच्छा लगा। अच्छा है, लेकिन पूरी तरह से आप को गुमराह करने के लिए प्रवण। अच्छा, यद्यपि। धन्यवाद।

+1

संभावित डुप्लिकेट [एक IEqualityComparer में एक प्रतिनिधि को लपेटें] (http://stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer) – nawfal

+0

@nawfal: यह एक अलग सवाल है। वे कुछ हद तक संबंधित हैं लेकिन अभी भी अलग हैं। हालांकि, यह एक बहुत अच्छा सवाल है। साझा करने के लिए धन्यवाद। मुझे यह बड़ा ही दिलचस्प लगा। :-) –

+0

ओह हाँ, अब मैं देखता हूं, लेकिन बहुत करीब: पी मैंने करीबी वोट वापस ले लिया, लेकिन मैं टिप्पणी जारी रखूंगा ताकि अन्य आगंतुक नोटिस कर सकें। एक बात, कृपया जवाब स्वीकार करें। मुझे लगता है कि शीर्ष वोट दिया गया जवाब आपके प्रश्न का उत्तर देता है। – nawfal

उत्तर

3

मैं सपने देखने के सिद्धांत के लिए वोट देता हूं।

आप किसी फ़ंक्शन को पास नहीं कर सकते जहां ऑब्जेक्ट की अपेक्षा की जाती है: सिस्टम का डेरिवेटिव। डिलीगेट (जो लैम्बडास है) उन इंटरफेस को लागू नहीं करते हैं।

जो आपने देखा है वह Converter<TInput, TOutput> प्रतिनिधि का उपयोग है, जिसे लैम्ब्डा द्वारा मॉडलिंग किया जा सकता है। Array.ConvertAll इस प्रतिनिधि का एक उदाहरण का उपयोग करता है।

10

आप एक Array.Sort विधि के लिए लैम्ब्डा प्रदान कर सकते हैं, क्योंकि इसे एक विधि की आवश्यकता होती है जो टाइप टी के दो ऑब्जेक्ट्स स्वीकार करता है और एक पूर्णांक देता है। इस प्रकार, आप निम्नलिखित परिभाषा (a, b) => a.CompareTo(b) का लैम्ब्डा प्रदान कर सकते हैं। एक उदाहरण एक पूर्णांक सरणी के उतरते तरह करना है:

int[] array = { 1, 8, 19, 4 }; 

// descending sort 
Array.Sort(array, (a, b) => -1 * a.CompareTo(b)); 
+0

क्या आप इसे और समझा सकते हैं? क्या यह आईसीओएमपेयर इंटरफ़ेस के लिए अद्वितीय व्यवहार है, या यह किसी भी इंटरफ़ेस पर काम करेगा जिसमें केवल एक ही विधि है? – StriplingWarrior

+6

@Stripling, मेरा मानना ​​है कि यह वास्तव में अधिभार का उपयोग कर रहा है जो 'तुलना ' स्वीकार करता है, क्योंकि 'तुलना' एक प्रतिनिधि है जो दो मानकों को स्वीकार करता है और पूर्णांक देता है। इस प्रकार, एक वैध लैम्ब्डा प्रदान करना इस अधिभार के लिए अर्हता प्राप्त करता है। –

2

इन विधियों भार के कि एक इंटरफेस के बजाय एक प्रतिनिधि को स्वीकार नहीं है, लेकिन:

  • आप आम तौर पर एक सरल प्रकार लौट सकते हैं प्रतिनिधि के माध्यम से प्रमुख आप इसी तरह Enumerable.OrderBy
  • के पास, आप Enumerable.SequenceEqual
  • कॉल करने से पहले Enumerable.Select कह सकते हैं यह एक आवरण है किलागू करता है लिखने के लिए सरल होना चाहिएFunc<T, T, bool> के मामले में
  • एफ # आप एक लैम्ब्डा :)
3

आप इसे सीधे पारित नहीं हो सकता के मामले में इंटरफ़ेस की इस तरह लागू लेकिन आप एक LambdaComparer वर्ग है कि एक Func<T,T,int> excepts को परिभाषित करते हुए ऐसा कर सकता है की सुविधा देता है और फिर इसका उपयोग CompareTo में करता है।

यह काफी संक्षिप्त नहीं है लेकिन आप इसे Func पर कुछ रचनात्मक विस्तार विधियों के माध्यम से छोटा कर सकते हैं।

5
public class Comparer2<T, TKey> : IComparer<T>, IEqualityComparer<T> 
{ 
    private readonly Expression<Func<T, TKey>> _KeyExpr; 
    private readonly Func<T, TKey> _CompiledFunc 
    // Constructor 
    public Comparer2(Expression<Func<T, TKey>> getKey) 
    { 
     _KeyExpr = getKey; 
     _CompiledFunc = _KeyExpr.Compile(); 
    } 

    public int Compare(T obj1, T obj2) 
    { 
     return Comparer<TKey>.Default.Compare(_CompiledFunc(obj1), _CompiledFunc(obj2)); 
    } 

    public bool Equals(T obj1, T obj2) 
    { 
     return EqualityComparer<TKey>.Default.Equals(_CompiledFunc(obj1), _CompiledFunc(obj2)); 
    } 

    public int GetHashCode(T obj) 
    { 
     return EqualityComparer<TKey>.Default.GetHashCode(_CompiledFunc(obj)); 
    } 
} 

इस

ArrayList.Sort(new Comparer2<Product, string>(p => p.Name)); 
+2

क्यों न केवल 'Func ' स्वीकार करें? – AlexFoxGill

+0

[बस 'Func '] (http://stackoverflow.com/a/1239337/2122718) का उपयोग करके, लेकिन एक्सप्रेसस्टियन – marbel82

18

की तरह उपयोग मैं बहुत यकीन है कि क्या यह वास्तव में उपयोगी है, के रूप में मैं एक IComparer उम्मीद बेस लाइब्रेरी में ज्यादातर मामलों के लिए लगता है कि वहाँ एक अधिभार है कि एक तुलना की उम्मीद है नहीं कर रहा हूँ ... लेकिन सिर्फ रिकार्ड के लिए:

नेट 4.5 में वे एक तुलना से एक IComparer प्राप्त करने के लिए एक विधि जोड़ दिया है: Comparer.Create

ताकि आप इसे अपने लैम्ब्डा को पास कर सकें और आईसीओम्पियर प्राप्त कर सकें।

+0

का उपयोग करने के तरीके के लिए धन्यवाद। यह .NET 4 के लिए एक्सटेंशन विधि जोड़ने के लिए अपेक्षाकृत सरल होगा एक ही चीज़ को पूरा करता है। – jessehouwing

+4

क्या समानता कॉम्पैडर के लिए कुछ समान उपलब्ध है? इसमें कोई विधि नहीं है लेकिन तुलनात्मक के लिए यह उपयोगी विधि जोड़ने के लिए बहुत अजीब लगता है और समानता कॉम्पैयर – rdans

+2

@rdans 'समानता कॉम्पैडर 'विभिन्न हस्ताक्षर का उपयोग करता है, और,' GetHashCode' विधि का भी उपयोग करता है। तो आप इसके लिए आसानी से तुलनात्मक नहीं बना सकते हैं। – VMAtm

16

मैं समाधान के लिए वेब पर भी जा रहा था, लेकिन मुझे कोई संतोषजनक नहीं मिला। तो मैं एक सामान्य EqualityComparerFactory बना लिया है:

public static class EqualityComparerFactory<T> 
{ 
    private class MyComparer : IEqualityComparer<T> 
    { 
     private readonly Func<T, int> _getHashCodeFunc; 
     private readonly Func<T, T, bool> _equalsFunc; 

     public MyComparer(Func<T, int> getHashCodeFunc, Func<T, T, bool> equalsFunc) 
     { 
      _getHashCodeFunc = getHashCodeFunc; 
      _equalsFunc = equalsFunc; 
     } 

     public bool Equals(T x, T y) 
     { 
      return _equalsFunc(x, y); 
     } 

     public int GetHashCode(T obj) 
     { 
      return _getHashCodeFunc(obj); 
     } 
    } 

    public static IEqualityComparer<T> CreateComparer(Func<T, int> getHashCodeFunc, Func<T, T, bool> equalsFunc) 
    { 
     if (getHashCodeFunc == null) 
      throw new ArgumentNullException("getHashCodeFunc"); 
     if (equalsFunc == null) 
      throw new ArgumentNullException("equalsFunc"); 

     return new MyComparer(getHashCodeFunc, equalsFunc); 
    } 
} 

विचार है, कि CreateComparer विधि दो तर्क लेता है: GetHashCode (टी) और बराबर (टी, टी)

उदाहरण के लिए एक प्रतिनिधि के लिए एक प्रतिनिधि :

class Person 
{ 
    public int Id { get; set; } 
    public string LastName { get; set; } 
    public string FirstName { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var list1 = new List<Person>(new[]{ 
      new Person { Id = 1, FirstName = "Walter", LastName = "White" }, 
      new Person { Id = 2, FirstName = "Jesse", LastName = "Pinkman" }, 
      new Person { Id = 3, FirstName = "Skyler", LastName = "White" }, 
      new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" }, 
     }); 

     var list2 = new List<Person>(new[]{ 
      new Person { Id = 1, FirstName = "Walter", LastName = "White" }, 
      new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" }, 
     }); 


     // We're comparing based on the Id property 
     var comparer = EqualityComparerFactory<Person>.CreateComparer(a => a.Id.GetHashCode(), (a, b) => a.Id==b.Id); 
     var intersection = list1.Intersect(list2, comparer).ToList(); 
    } 
} 
मामले में
1

यदि आप और संभवतः दो अलग अलग तत्व प्रकार लैम्ब्डा साथ प्रयोग के लिए इस समारोह की जरूरत है:

static class IEnumerableExtensions 
{ 
    public static bool SequenceEqual<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> comparer) 
    { 
     if (first == null) 
      throw new NullReferenceException("first"); 

     if (second == null) 
      throw new NullReferenceException("second"); 

     using (IEnumerator<T1> e1 = first.GetEnumerator()) 
     using (IEnumerator<T2> e2 = second.GetEnumerator()) 
     { 
      while (e1.MoveNext()) 
      { 
       if (!(e2.MoveNext() && comparer(e1.Current, e2.Current))) 
        return false; 
      } 

      if (e2.MoveNext()) 
       return false; 
     } 

     return true; 
    } 
} 
संबंधित मुद्दे