2012-01-04 13 views
15

पास करने के बारे में उलझन में अभिव्यक्तियों और Funcs कैसे काम करता है के बीच अंतर को समझने में मुझे कुछ परेशानी हो रही है। यह समस्या कर दिया जब किसी से कोई विधि हस्ताक्षर बदल दिया है:अभिव्यक्ति बनाम Func तर्क

public static List<Thing> ThingList(Func<Thing, bool> aWhere) 

करने के लिए

public static List<Thing> ThingList(Expression<Func<Thing, bool>> aWhere) 

कौन सा मेरी बुला कोड को तोड़ दिया। वर्ष बुला कोड (जो काम किया) इस तरह देखा:

 ... 
     object y = new object(); 
     Func<Thing, bool> whereFunc = (p) => p == y; 
     things = ThingManager.ThingList(whereFunc); 

नए कोड (जो काम नहीं करता है) इस तरह दिखता है:

 ... 
     object x = new object(); 
     Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
     things = ThingManager.ThingList(whereExpr); 

यह ThingList अंदर विफल रहता है (...) पर लाइन अभिव्यक्ति का उपयोग:

 var query = (from t in context.Things.Where(aWhere) 
     ... 

रनटाइम त्रुटि के साथ:

Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context. 

यह उदाहरण दूषित है, लेकिन मेरा अनुमान है कि यह स्थानीय ऑब्जेक्ट वेरिएबल x के साथ कुछ करने के लिए अभिव्यक्ति में ठीक से "प्रतिलिपि" नहीं है।

क्या कोई यह बता सकता है कि सामान्य रूप से इस स्थिति को कैसे संभाला जाए और Func क्यों काम करता है लेकिन Expression नहीं है?

उत्तर

11

लगभग निश्चित रूप से बदलाव का कारण अंतर्निहित दुकान है, जो आपके context पीठ में "पुश" अपने विधेय का मूल्यांकन करने के लिए किया गया था। सभी Things को मेमोरी में लाने के बजाय और Func<Thing,bool> का उपयोग करके यह तय करने के लिए कि किसने रखा है, बदले गए एपीआई के लेखक ने IQueryable का उपयोग करने का निर्णय लिया, और इसके लिए Expression<Func<Thing,bool>> की आवश्यकता थी।

आप त्रुटि की उत्पत्ति पर सही हैं: मेमोरी भविष्यवाणी के विपरीत, IQueryable उन वस्तुओं का उपयोग नहीं कर सकता जो इसे नहीं जानते हैं, उदा। object के मनमाने ढंग से उदाहरण।

आपको अपने लक्षित डेटा स्टोर द्वारा समर्थित डेटा प्रकारों की संदर्भित वस्तुओं के संदर्भों से बचने के लिए अभिव्यक्ति को बदलने के लिए क्या करना है (मुझे लगता है कि अभिव्यक्ति अंततः एक इकाई फ्रेमवर्क या एक लिंक 2 एसक्यूएल संदर्भ में अपना रास्ता बनाती है)। उदाहरण के लिए, बजाय

object x = new object(); 
Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
things = ThingManager.ThingList(whereExpr); 

कह के आप कहना चाहिए

Thing x = new Thing {id = 123}; 
Expression<Func<Thing, bool>> whereExpr = (p) => p.id == x.id; 
things = ThingManager.ThingList(whereExpr); 

(अपने समर्थन की दुकान लगभग निश्चित रूप से पूर्णांकों समझता है)

+0

हाँ, यह एक इकाई की रूपरेखा के लिए अपनी राह बनाता है। मुझे लगता है कि मुझे अभिव्यक्ति के लिए दो विधियां, एक और फंक के लिए एक जहां आवश्यक हो वहां उपयोग करना होगा। – Erix

6

अभिव्यक्ति और समारोह के बीच अंतर के सही उत्तर यहाँ में वर्णित है: Difference between Expression<Func<>> and Func<>

एक त्वरित समाधान का यह काम फिर से अभिव्यक्ति एक समारोह में वापस संकलित करने के लिए किया जाएगा बनाने के लिए।

var query = (from t in context.Things.Where(aWhere.Compile()) 
संबंधित मुद्दे