2009-05-08 14 views
10

के पैरामीटर के लिए उपयोग नहीं किया जा सकता है। मैं किसी भी प्रकार की तुलना करने के लिए समानता (==) ऑपरेटर को सी # में ओवरराइड करने का प्रयास कर रहा हूं एक कस्टम प्रकार (कस्टम प्रकार वास्तव में एक आवरण के आसपास एक रैपर/बॉक्स है)। अब अगर मैं एक फोन की तरह बनाने केलिंक और समानता ऑपरेटर: प्रकार 'System.Int32' प्रकार का अभिव्यक्ति 'System.Object'

internal sealed class Nothing 
{ 
    public override bool Equals(object obj) 
    { 
     if (obj == null || obj is Nothing) 
      return true; 
     else 
      return false; 
    } 

    public static bool operator ==(object x, Nothing y) 
    { 
     if ((x == null || x is Nothing) && (y == null || y is Nothing)) 
      return true; 
     return false; 
    } 
    ... 
} 

:

Nothing n = new Nothing(); 
bool equal = (10 == n); 

यह पूरी तरह से ठीक काम करता है

तो मैं इस किया है। हालांकि, अगर मैं एक Linq अभिव्यक्ति पेड़ के माध्यम से इस एक ही बात करने की कोशिश:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(new Nothing(), typeof(Nothing)) 
); 

यह अपवाद फेंकता है:

System.ArgumentException : Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean op_Equality(System.Object, PARTSFinder.Rules.Runtime.RulesNothing)' 
    at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodInfo method, ReadOnlyCollection`1& arguments) 
    at System.Linq.Expressions.Expression.ValidateCallArgs(Expression instance, MethodInfo method, ReadOnlyCollection`1& arguments) 
    at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments) 
    at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments) 
    at System.Linq.Expressions.ExpressionCompiler.GenerateBinaryMethod(ILGenerator gen, BinaryExpression b, StackType ask) 

क्यों आधार प्रणाली Int32 वस्तु में बदल सकते हैं पर कोई भी विचार है, लेकिन Linq नहीं कर सकता, या मैं इसे कैसे ठीक कर सकता हूं?

यह पूरी बात क्योंकि Linq देखें भी Int32 तुलना नहीं कर सकते पहली जगह में वस्तु के लिए:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(null) 
); 

उन्होंने कहा कि "System.Int32" और "सिस्टम के लिए कोई तुलना ऑपरेटर है कि वहाँ एक अपवाद फेंकता। ऑब्जेक्ट "।


त्वरित फॉलोअप:

निम्न समस्या के बिना काम करते हैं:

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)), 
    Expression.Constant(new Nothing(), typeof(Nothing)) 
); 

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)), 
    Expression.Constant(null) 
); 

तो विशेष रूप से वस्तु के लिए सब कुछ कास्टिंग। तो क्या लिंक सिर्फ आंतरिक रूप से विरासत को संभालने में सक्षम नहीं है? यही बहुत कष्टप्रद ...


फॉलोअप # 2:

मैं भी एक कस्टम तुलना विधि का उपयोग करने की कोशिश की:

exp = Expression.Equal(
    Expression.Constant(10), 
    Expression.Constant(null), 
    false, 
    this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static) 
); 

    public static bool ValueEquals(object x, object y) 
    { 
     if (x == null && y == null) 
      return true; 
     if (x.GetType() != y.GetType()) 
      return false; 
     return x == y; 
    } 

यह भी एक अपवाद फेंकता है:

System.InvalidOperationException : The operands for operator 'Equal' do not match the parameters of method 'ValueEquals'. 
    at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull) 

लेकिन फिर से काम करने के लिए सीधे सब कुछ कास्टिंग:

exp = Expression.Equal(
    Expression.Constant(10, typeof(object)), 
    Expression.Constant(null, typeof(object)), 
    false, 
    this.GetType().GetMethod("ValueEquals", BindingFlags.Public | BindingFlags.Static) 
); 

तो मुझे लगता है कि मेरे पास अपना कामकाज है ... ऑब्जेक्ट करने के लिए सब कुछ डालें और एक कस्टम तुलना विधि का उपयोग करें। मुझे अभी भी हैरान है कि लिंक सामान्य रूप से सामान्य सी # के रूप में रूपांतरण नहीं करता है।

+6

"तो Linq सिर्फ विरासत आंतरिक रूप से संभाल नहीं करता है?बहुत परेशान है ... "हाँ, यह कष्टप्रद है लेकिन यह एक अच्छे कारण के लिए है। अभिव्यक्ति वृक्ष पुस्तकालय सी # और वीबी दोनों से अभिव्यक्तियों के साथ काम करते हैं, और, उस मामले के लिए, ऐसी किसी भी अन्य भाषा जिसमें अभिव्यक्तियां हैं। यदि हमने सी # रूपांतरण नियमों को समानता को हल करने वाले कोड में बेक किया, तो हम वीबी से आने वाले अभिव्यक्तियों के लिए गलत काम कर रहे हैं। इसलिए हम न तो करते हैं - आपको स्पष्ट अभिव्यक्तियों को पारित करने की आवश्यकता होती है, ताकि संकल्प भाषा हो -agnostic –

+0

(जोड़ा गया आपकी टिप्पणी फिर से देखें) –

+0

ठीक है, आपको एरिक लिपर्ट की तुलना में इस विषय पर बेहतर अधिकार नहीं मिलेगा! –

उत्तर

9

शून्य के साथ क्या गलत है? पुन लापता int बनाम null, int? कोशिश:

exp = Expression.Equal(
    Expression.Constant(10, typeof(int?)), 
    Expression.Constant(null, typeof(int?)) 
); 
+0

मेरा मुद्दा यह है कि मैं वास्तव में प्रकारों को नहीं जानता। अभिव्यक्ति। कॉन्स्टेंट को एक शब्दकोश में मानों से गतिशील रूप से बनाया जा रहा है। समस्या तब होती है जब कुछ मौजूद नहीं होता है शब्दकोश, यह शून्य वापस आता है। – CodingWithSpike

+0

मेरी उपरोक्त टिप्पणी को और स्पष्ट करने के लिए, कोई "x" और "y" की तुलना करने का प्रयास कर सकता है, और कोड "एक्स" और "वाई" को एक शब्दकोश से बाहर ले जाएगा, और एक अभिव्यक्ति बना देगा। कॉन्स्टेंट (dict ["x" ]) और अभिव्यक्ति। कॉन्स्टेंट (dict ["y"]) और समान() उन्हें करने का प्रयास करें। – CodingWithSpike

+1

ठीक है, "ऑब्जेक्ट" का उपयोग अभिव्यक्ति के साथ थोड़ा जोखिम भरा है; इसे सही ओवरलोड का उपयोग करने के लिए प्रकारों को साबित करने की आवश्यकता है ... आप शायद कुछ विशेष नियमों में डाल सकते हैं ताकि यदि एक ऑपरेंड शून्य हो तो आप दूसरे ऑपरेंड से टाइप का उपयोग करें। –

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