2013-09-02 8 views
12

पर अनावश्यक रूपांतरण बाइट्स और शॉर्ट्स के साथ काम करते समय अभिव्यक्ति के पेड़ एक अनावश्यक रूपांतरण बनाने लगते हैं, वे दोनों पक्षों (उदाहरण के लिए बाइनरी अभिव्यक्तियों में) int32 में परिवर्तित करते हैं।अभिव्यक्ति पेड़ - int32

यह मैंने देखा है कि कुछ लिंक प्रदाताओं में यह एक मुद्दा है, प्रत्येक को मूल अभिव्यक्ति प्राप्त करने के लिए इस अनावश्यक परत को छीलना है। (NHibernate इस परत को नहीं हटाता है और SQL क्वेरी में एक भयानक CAST बनाता है)।

// no conversion 
Console.WriteLine((Expression<Func<int, int, bool>>) ((s, s1) => s == s1)); 
// converts to int32 
Console.WriteLine((Expression<Func<short, short, bool>>) ((s, s1) => s == s1)); 
// converts to int32 
Console.WriteLine((Expression<Func<byte, byte, bool>>) ((s, s1) => s == s1)); 

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

तो सवाल यह है कि, इस व्यवहार का कारण क्या है?

संपादित .net 4.0 64 बिट, एक ही 4.5 64 बिट

+1

सी # कंपाइलर का कौन सा संस्करण आप काम कर रहे हैं? इस चरण में मेरा एकमात्र अनुमान इस पंक्ति के साथ होगा कि 'int' समानता .NET में आदिम संचालन में एक निर्माण है जिसे केवल' int 'के लिए परिभाषित किया गया है (छोटे प्रकार के मूल्यांकन स्टैक पर मौजूद नहीं हो सकते हैं) और यह किसी भी तरह कारक है यहाँ। –

उत्तर

5

यह वास्तव में दिलचस्प बात यह है करने के लिए लागू होता है; दुर्भाग्यवश, अभिव्यक्ति-वृक्ष संकलक के नियम औपचारिक रूप से निर्दिष्ट नहीं हैं - विनिर्देशन में एक संक्षिप्त "कहीं और हैं", लेकिन: वे वास्तव में नहीं हैं।

यह एक समस्या खड़ी कर रहा है, तो आप को पहचानने और इसे हटाने के लिए कोशिश कर सकते - आदि नीचे की तरह कुछ है, जो 100% अपरीक्षित है और उपयोग-में खुद-जोखिम वाला है,:

static void Main() 
{ 
    Console.WriteLine(((Expression<Func<short, short, bool>>)((s, s1) => s == s1)).Unmunge()); 
    Console.WriteLine(((Expression<Func<byte, byte, bool>>)((s, s1) => s == s1)).Unmunge()); 
} 
static Expression<T> Unmunge<T>(this Expression<T> expression) 
{ 
    return (Expression<T>)RedundantConversionVisitor.Default.Visit(expression); 
} 
class RedundantConversionVisitor : ExpressionVisitor 
{ 
    private RedundantConversionVisitor() { } 
    public static readonly RedundantConversionVisitor Default = new RedundantConversionVisitor(); 
    protected override Expression VisitBinary(BinaryExpression node) 
    { 
     if(node.Type == typeof(bool) && node.Method == null 
      && node.Left.NodeType == ExpressionType.Convert && node.Right.NodeType == ExpressionType.Convert 
      && node.Left.Type == node.Right.Type) 
     { 
      UnaryExpression lhs = (UnaryExpression)node.Left, rhs = (UnaryExpression)node.Right; 
      if (lhs.Method == null && rhs.Method == null && lhs.Operand.Type == rhs.Operand.Type) 
      { 
       // work directly on the inner values 
       return Expression.MakeBinary(node.NodeType, lhs.Operand, rhs.Operand, node.IsLiftedToNull, node.Method); 
      } 
     } 
     return base.VisitBinary(node); 
    } 
} 

आउटपुट से पहले:

(s, s1) => (Convert(s) == Convert(s1)) 
(s, s1) => (Convert(s) == Convert(s1)) 

आउटपुट के बाद:

(s, s1) => (s == s1) 
(s, s1) => (s == s1) 
+0

आपके विस्तृत उत्तर के लिए धन्यवाद, लेकिन सवाल यह है कि ** ** यह क्यों है। यह लिंक प्रदाताओं के बीच एक आम मुद्दा है जो समझ में नहीं आता है ... – MoranB

+2

@ मॉरनबी यूप, मैं असहमत नहीं हूं। हालांकि, किसी विनिर्देश की अनुपस्थिति में एकमात्र उत्तर मैं आपको दे सकता हूं "क्योंकि जिस तरह से इसे कोड किया गया है"। Roslyn के माध्यम से यह देखने के लिए वास्तव में दिलचस्प होगा कि Roslyn एक ही चीज़ करता है - और वास्तव में, शायद एमसीएस/जीएमसीएस (मोनो कंपाइलर)। इसके अलावा, मैं सोच रहा हूं कि "दोष मैड्स"; पी –

+1

@MarcGravell मुझे रोज़लिन और मोनो दोनों से एक ही परिणाम ('कनवर्ट' के साथ) मिल रहा है। – svick

3

आपके प्रश्न का उत्तर करने के लिए:

क्यों अभिव्यक्ति पेड़ ... जब बाइट्स और शॉर्ट्स के साथ काम कर एक अनावश्यक रूपांतरण का निर्माण करने लगते हैं तो सवाल है, क्या इस व्यवहार के लिए कारण क्या है?

जवाब वास्तव में छिपा हुआ है, कि सी # प्रकार short, ushort, byte और sbyte कमी गणित, तुलना ... ऑपरेटरों:

निकालें: 4.1.5 Integral types

के लिए द्विआधारी +, -, *, /%, &, ^, |, ==,! =,>, <,> =, और < = ऑपरेटर, ऑपरेटरों टाइप करने के लिए T, जहां Tint, uint, long के पहले है, और ulong कि पूरी तरह से दोनों ऑपरेंड के सभी संभव मूल्यों का प्रतिनिधित्व कर सकते हैं बदल रहे हैं। ऑपरेशन को T के परिशुद्धता का उपयोग करके किया जाता है, और परिणाम का प्रकार T (या संबंधपरक ऑपरेटरों के लिए बूल) है। एक ऑपरेंड के लिए प्रकार लंबा होने की अनुमति नहीं है और दूसरे बाइनरी ऑपरेटरों के साथ उलझन के प्रकार के लिए अनुमति नहीं है।

7.9.1 Integer comparison operators उपलब्ध ऑपरेटरों और उनके ऑपरेंड का वर्णन करता है

bool operator ==(int x, int y); 
bool operator ==(uint x, uint y); 
bool operator ==(long x, long y); 
bool operator ==(ulong x, ulong y); 
... // other operators, only for int, uint, long, ulong 

रूपांतरण संकलक (कारण है कि आप का निर्माण करने के लिए कि स्पष्ट रूपांतरण के बिना सफल होने)

से आप के लिए किया जाता है क्योंकि वहाँ कोई ऑपरेटरों कम से कम काम कर रहे हैं ... रूपांतरण लागू किया जाना चाहिए। और निश्चित रूप से, यह बाद में LINQ प्रदाता पर निर्भर करता है, इस तरह की "अभिव्यक्ति" को SQL में कैसे परिवर्तित करें।

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