सामान्य प्रकारों के मूल्यों की तुलना कैसे करें?


81

मैं जेनेरिक प्रकारों के मूल्यों की तुलना कैसे करूं?

मैंने इसे एक न्यूनतम नमूने में घटा दिया है:

public class Foo<T> where T : IComparable
{
    private T _minimumValue = default(T);

    public bool IsInRange(T value) 
    {
        return (value >= _minimumValue); // <-- Error here
    }
}

त्रुटि है:

ऑपरेटर '> =' को 'T' और 'T' प्रकार के ऑपरेंड पर लागू नहीं किया जा सकता है।

पृथ्वी पर क्या!? Tपहले से ही करने के लिए विवश किया जाता है IComparable, और तब भी जब यह मूल्य प्रकार (करने के लिए बाधित where T: struct), हम अभी भी ऑपरेटरों के किसी भी लागू नहीं कर सकते <, >, <=, >=, ==या !=। (मुझे पता है कि इसमें शामिल वर्कअराउंड Equals()मौजूद हैं ==और !=, लेकिन यह रिलेशनल ऑपरेटरों के लिए मदद नहीं करता है)।

तो, दो सवाल:

  1. हम इस अजीब व्यवहार का निरीक्षण क्यों करते हैं? हमें जेनेरिक प्रकारों के मूल्यों की तुलना करने से क्या है ज्ञात हैं IComparable? क्या यह किसी तरह से सामान्य बाधाओं के पूरे उद्देश्य को नहीं हराता है?
  2. मैं इसे कैसे हल करूं, या कम से कम इसके आसपास काम करूं?

(मुझे पता है कि पहले से ही इस सरल समस्या से संबंधित कुछ मुट्ठी भर सवाल हैं - लेकिन कोई भी सूत्र इतना विस्तृत या व्यावहारिक जवाब नहीं देता है, इसलिए यहाँ है।)

जवाबों:


96

IComparable>=ऑपरेटर को ओवरलोड नहीं करता है । आपको उपयोग करना चाहिए

value.CompareTo(_minimumValue) >= 0

7
महान, यह काम करता है (और इसे बताता है, निश्चित रूप से) - बहुत बहुत धन्यवाद! लेकिन यह थोड़ा असंतोषजनक है, और सवाल छोड़ देता है: क्यों IComparable तुलना ऑपरेटरों को अधिभार नहीं देता है? क्या यह एक सचेत और जानबूझकर किया गया डिजाइन निर्णय है, एक अच्छे कारण के साथ - या ऐसा कुछ जिसे फ्रेमवर्क के डिजाइन में अनदेखा किया गया था? आखिरकार, 'x.CompareTo (y)> = 0' 'x> = y' की तुलना में कम पठनीय है, नहीं?
21

मैं निश्चित रूप से आपकी बात मानता हूं। मुझे लगता है कि समस्या यह है कि ऑपरेटर स्थिर हैं जिसका अर्थ है कि वे एक इंटरफ़ेस में फिट नहीं हो सकते हैं। मैं न्याय नहीं करूंगा कि यह एक अच्छा विकल्प है या नहीं, लेकिन मुझे लगता है कि उचित नाम वाले तरीकों को ऑपरेटरों की तुलना में पढ़ना आसान होता है जब प्रकार गैर आदिम होते हैं; हालांकि यह स्वाद का मामला है।
फॉरेस्टर

5
@gstercken: IComparableतुलना संचालकों को ओवरलोड करने के साथ एक समस्या यह है कि ऐसी स्थितियां हैं जो X.Equals(Y)झूठी होनी चाहिए, लेकिन X.CompareTo(Y)शून्य लौट जाना चाहिए (यह सुझाव देते हुए कि कोई भी तत्व दूसरे से बड़ा नहीं है) उदाहरण के ExpenseItemलिए TotalCost, सम्मान के साथ एक प्राकृतिक आदेश हो सकता है, और हो सकता है व्यय वस्तुओं के लिए कोई प्राकृतिक ऑर्डरिंग नहीं है, जिसकी लागत समान है, लेकिन इसका मतलब यह नहीं है कि प्रत्येक व्यय आइटम जिसकी कीमत $ 3,141.59 है, को उसी लागत वाले प्रत्येक अन्य आइटम के बराबर माना जाना चाहिए।
सुपरकैट

1
@gstercken: मौलिक रूप से, ऐसी कई चीजें हैं जो ==तार्किक रूप से मतलब कर सकती हैं। कुछ संदर्भों में, झूठे होते X==Yहुए भी सच होना संभव X.Equals(Y)है, और जबकि अन्य संदर्भों में X==Yगलत हो सकता है जबकि X.Equals(Y)सच है। ऑपरेटरों इंटरफेस, अधिक भार के लिए अतिभारित किया जा सकता है यहां तक कि अगर <, <=, >और >=के मामले में IComparable<T>एक धारणा है कि दे सकता है ==और !=भी इस तरह के मामले में अतिभारित किया जाएगा। यदि C # था, तो vb की तरह, ==क्लास के प्रकारों के उपयोग को रोक दिया गया था जिसके लिए यह अतिभारित नहीं था जो कि बहुत बुरा नहीं था, लेकिन ...
Supercat

2
... alas C # ने ==एक अधिभार समानता ऑपरेटर और गैर-अधिभार संदर्भ-समतुल्य परीक्षण दोनों का प्रतिनिधित्व करने के लिए टोकन का उपयोग करने का निर्णय लिया ।
सुपरकैट

35

ऑपरेटर के ओवरलोडिंग की समस्या

दुर्भाग्य से, इंटरफेस में अतिभारित ऑपरेटर नहीं हो सकते। इसे अपने कंपाइलर में टाइप करने की कोशिश करें:

public interface IInequalityComaparable<T>
{
    bool operator >(T lhs, T rhs);
    bool operator >=(T lhs, T rhs);
    bool operator <(T lhs, T rhs);
    bool operator <=(T lhs, T rhs);
}

मुझे नहीं पता कि उन्होंने इसकी अनुमति क्यों नहीं दी, लेकिन मैं यह अनुमान लगा रहा हूं कि यह भाषा की परिभाषा को जटिल कर रही है, और उपयोगकर्ताओं के लिए सही तरीके से लागू करना कठिन होगा।

या तो, या डिजाइनरों ने दुरुपयोग की संभावना को पसंद नहीं किया। उदाहरण के लिए, एक >=पर तुलना करने की कल्पना करो class MagicMrMeow। या ए पर भीclass Matrix<T> । परिणाम का दो मूल्यों के बारे में क्या मतलब है ?; खासकर जब कोई अस्पष्टता हो सकती है?

आधिकारिक काम के आसपास

चूंकि उपरोक्त इंटरफ़ेस कानूनी नहीं है, इसलिए हमारे पास IComparable<T>समस्या के आसपास काम करने के लिए इंटरफ़ेस है। यह संचालकों को लागू नहीं करता है, और केवल एक विधि को उजागर करता है,int CompareTo(T other);

Http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx देखें

intपरिणाम वास्तव में एक त्रि-बिट, या एक त्रि-आम है (एक के समान Booleanहै, लेकिन तीन राज्यों के साथ)। यह तालिका परिणामों का अर्थ बताती है:

Value              Meaning

Less than zero     This object is less than
                   the object specified by the CompareTo method.

Zero               This object is equal to the method parameter.

Greater than zero  This object is greater than the method parameter.

काम के इर्द-गिर्द

इसके बराबर करने के लिए value >= _minimumValue, आपको इसके बजाय लिखना होगा:

value.CompareTo(_minimumValue) >= 0

2
आह, सही - समझ में आता है। मैं भूल गया कि सी # में इंटरफेस ऑपरेटरों को अधिभार नहीं दे सकता है।
gstercken

32

यदि valueशून्य हो सकता है तो वर्तमान उत्तर विफल हो सकता है। इसके बजाय कुछ इस तरह से उपयोग करें:

Comparer<T>.Default.Compare(value, _minimumValue) >= 0

1
पारितोषिक के लिए धन्यवाद। मुझे कुछ विस्तार विधियों के लिए इसकी आवश्यकता थी, जिन पर मैं काम कर रहा था। निचे देखो।
InteXX

1
ठीक मिल गया। मैं बाधित नहीं किया गया था Tकरने के लिए IComparable। लेकिन आपकी टिप मुझे कूबड़ पर फिर भी मिली।
InteXX

6
public bool IsInRange(T value) 
{
    return (value.CompareTo(_minimumValue) >= 0);
}

जब IComparable जेनरिक के साथ काम कर रहे हैं, तो ऑपरेटर्स की तुलना में ऑपरेटर्स की तुलना में कम / अधिक सभी को कॉल में बदलना होगा। आप जो भी ऑपरेटर का उपयोग करेंगे, उसी क्रम में तुलना किए जाने वाले मानों को रखें और शून्य के खिलाफ तुलना करें। ( x <op> yहो जाता है x.CompareTo(y) <op> 0, जहां <op>है >, >=आदि)

इसके अलावा, मेरा सुझाव है कि आपके द्वारा उपयोग किए जाने वाले सामान्य अवरोध हो where T : IComparable<T>। अपने आप में IComparable का मतलब है कि वस्तु की तुलना किसी भी चीज के साथ की जा सकती है, एक ही प्रकार के अन्य के खिलाफ किसी वस्तु की तुलना करना शायद अधिक उचित है।


3

value >= _minimValueउपयोग Comparerवर्ग के बजाय :

public bool IsInRange(T value ) {
    var result = Comparer<T>.Default.Compare(value, _minimumValue);
    if ( result >= 0 ) { return true; }
    else { return false; }
}

Comparerजब कोई पहले से ही एक सामान्य बाधा है जिसे Tलागू करना होगा का उपयोग शुरू करें IComparable?
फ्रेड्रिक मोर

@ फ़्रेड्रिक जेनेरिक बाधाओं का निर्माण होता है। मैं उन्हें यहां छोड़ने से सहमत हूं।
मार्क ग्रेवल

2

जैसा कि दूसरों ने कहा है, किसी को तुलनात्मक पद्धति का स्पष्ट रूप से उपयोग करने की आवश्यकता है। कारण यह है कि कोई भी ऑपरेटरों के साथ इंटरफेस का उपयोग नहीं कर सकता है, यह संभव है कि एक वर्ग के लिए इंटरफेस की एक मनमानी संख्या को लागू करना संभव है, उनके बीच कोई स्पष्ट रैंकिंग नहीं है। मान लीजिए कि किसी ने "a = foo + 5;" जब फू ने छह इंटरफेस लागू किए, जो एक पूर्णांक दूसरे तर्क के साथ एक ऑपरेटर "+" को परिभाषित करते हैं; ऑपरेटर के लिए किस इंटरफ़ेस का उपयोग किया जाना चाहिए?

तथ्य यह है कि वर्गों कई इंटरफेस प्राप्त कर सकते हैं इंटरफेस बहुत शक्तिशाली बनाता है। दुर्भाग्य से, यह अक्सर एक व्यक्ति के बारे में अधिक स्पष्ट होने के लिए मजबूर करता है जो वास्तव में करना चाहता है।


1
मुझे नहीं लगता कि एमआई को ओवरलोड ऑपरेटरों के साथ कोई समस्या नहीं है क्योंकि यह नियमित तरीकों के साथ है। वे तरीकों के लिए सिर्फ अजीब वाक्यविन्यास हैं। तो आप उस समस्या को हल कर सकते हैं उन्हीं नियमों का उपयोग करके उन्हें इंटरफेस पर नियमित तरीकों के रूप में हल किया जाएगा। C # डिज़ाइन लक्ष्यों में से एक यह था कि यह C ++ प्रोग्रामर के लिए कुछ हद तक परिचित है, और ओवरलोडेड ऑपरेटरों को उस भाषा में नरक और वापस दुर्व्यवहार किया गया। मैं अनुमान लगा रहा हूं कि डिजाइनर उन नामित विधियों को पसंद करते हैं जो आपको उन तरीकों के इरादे के लिए किसी प्रकार के प्रलेखन देने के लिए मजबूर करती हैं।
मेरलिन मॉर्गन-ग्राहम

1

IComparableकेवल एक फ़ंक्शन को बुलाता है CompareTo()। इसलिए आप अपने द्वारा बताए गए किसी भी ऑपरेटर को लागू नहीं कर सकते


0

मैं जेनरिक के लिए कुछ अतिभारित विस्तार विधियों को बनाने के लिए पीटर हेडबर्ग के उत्तर का उपयोग करने में सक्षम था। ध्यान दें कि CompareToविधि यहाँ काम नहीं करती है, क्योंकि प्रकार Tअज्ञात है और वह इंटरफ़ेस प्रस्तुत नहीं करता है। उस ने कहा, मुझे कोई विकल्प देखने में दिलचस्पी है।

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

<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T))
  Instance.RemoveDuplicates(Function(X, Y) Comparer(Of T).Default.Compare(X, Y))
End Sub



<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparison As Comparison(Of T))
  Instance.RemoveDuplicates(New List(Of Comparison(Of T)) From {Comparison})
End Sub



<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparisons As List(Of Comparison(Of T)))
  Dim oResults As New List(Of Boolean)

  For i As Integer = 0 To Instance.Count - 1
    For j As Integer = Instance.Count - 1 To i + 1 Step -1
      oResults.Clear()

      For Each oComparison As Comparison(Of T) In Comparisons
        oResults.Add(oComparison(Instance(i), Instance(j)) = 0)
      Next oComparison

      If oResults.Any(Function(R) R) Then
        Instance.RemoveAt(j)
      End If
    Next j
  Next i
End Sub

--EDIT--

मैं सभी तरीकों पर विवश Tहोकर इसे साफ करने में सक्षम था IComparable(Of T), जैसा कि ओपी ने संकेत दिया था। ध्यान दें कि इस बाधा को Tलागू करने के लिए प्रकार की आवश्यकता होती है IComparable(Of <type>)

<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T As IComparable(Of T))(Instance As List(Of T))
  Instance.RemoveDuplicates(Function(X, Y) X.CompareTo(Y))
End Sub
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.