2008-11-04 7 views
39

आम तौर पर, सशर्त ऑपरेटर का उपयोग करते समय, यहां वाक्यविन्यास है:मैं सशर्त टर्नरी ऑपरेटर का उपयोग करके लैम्बडा के बीच सशर्त रूप से एक Func <> कैसे असाइन कर सकता हूं?

int x = 6; 
int y = x == 6 ? 5 : 9; 

कुछ भी फैंसी, बहुत सीधे आगे नहीं।

अब, चलिए एक Func प्रकार को Lambda असाइन करते समय इसका उपयोग करने का प्रयास करें। मुझे समझाएं:

Func<Order, bool> predicate = id == null 
    ? p => p.EmployeeID == null 
    : p => p.EmployeeID == id; 

यह वही वाक्यविन्यास है, और काम करना चाहिए? सही? किसी कारण से ऐसा नहीं करता है। कंपाइलर यह अच्छा गुप्त संदेश देता है:

त्रुटि 1 सशर्त अभिव्यक्ति का प्रकार निर्धारित नहीं किया जा सकता है क्योंकि 'लैम्ब्डा अभिव्यक्ति' और 'लैम्ब्डा अभिव्यक्ति'

के बीच कोई अंतर्निहित रूपांतरण नहीं है, फिर मैं आगे बढ़ गया और वाक्यविन्यास बदल दिया और इस तरह यह काम किया:

Func<Order, bool> predicate = id == null 
    ? predicate = p => p.EmployeeID == null 
    : predicate = p => p.EmployeeID == id; 

मैं सिर्फ उत्सुक हूं कि यह पहली बार क्यों काम नहीं करता है?

(साइड नोट: मुझे इस कोड की आवश्यकता नहीं है, क्योंकि मुझे पता चला है कि शून्य के विरुद्ध एक इंट मान की तुलना करते समय, आप ऑब्जेक्ट का उपयोग करते हैं। एक्वाल्स)

उत्तर

40

आप एक विशेष लक्ष्य के लिए एक लैम्ब्डा अभिव्यक्ति में बदल सकते हैं प्रतिनिधि प्रकार, लेकिन सशर्त अभिव्यक्ति के प्रकार को निर्धारित करने के लिए, कंपाइलर को दूसरे और तीसरे ऑपरेटरों में से प्रत्येक के प्रकार को जानने की आवश्यकता है। हालांकि वे दोनों "लैम्ब्डा अभिव्यक्ति" हैं, जबकि एक से दूसरे में कोई रूपांतरण नहीं है, इसलिए संकलक कुछ भी उपयोगी नहीं कर सकता है। -

मैं एक काम के उपयोग की अनुशंसा नहीं होता, फिर भी एक डाली अधिक स्पष्ट है:

Func<Order, bool> predicate = id == null 
    ? (Func<Order, bool>) (p => p.EmployeeID == null) 
    : p => p.EmployeeID == id; 

ध्यान दें कि आप केवल एक संकार्य के लिए यह प्रदान करने की आवश्यकता है, तो संकलक दूसरे से रूपांतरण प्रदर्शन कर सकते हैं लैम्ब्डा अभिव्यक्ति।

+0

मुझे आश्चर्य है कि, अगर संकलक इस अनुमान लगा सकते हैं: 'समारोह विधेय = पी => p.EmployeeID == id', कैसे यह मुसीबत यह निष्कर्ष निकालते हैं:' समारोह विधेय = आईडी == बातिल ? (Func ) (p => p.EmployeeID == null) : p => p.EmployeeID == id; '? मेरा मतलब है कि यह 'predicate' की घोषणा के माध्यम से दूसरे और तीसरे ऑपरेटरों के लिए आवश्यक प्रकार जानता है। – GDS

+0

@ जीडीएस: लैम्ब्डा अभिव्यक्ति से प्रतिनिधि प्रकार में एक निहित रूपांतरण है, यही कारण है कि पहला संस्करण काम करता है। लेकिन 'predicate' की घोषणा सशर्त अभिव्यक्ति के लिए प्रकार अनुमान को प्रभावित नहीं करती है। भाषा विनिर्देश मूल रूप से कहता है कि सशर्त अभिव्यक्ति का प्रकार केवल ऑपरेटरों के माध्यम से अवरुद्ध होना चाहिए। –

+0

तब मुझे आश्चर्य है, टर्नरी ऑपरेटर की इतनी आवश्यकता क्यों होगी। यह एक चर या एक अभिव्यक्ति के सशर्त मूल्यांकन के लिए दूसरे या तीसरे ऑपरेंड का एक सशर्त असाइनमेंट है। जब तक मुझे कुछ याद नहीं आ रहा है, प्रत्यक्ष कार्य या मूल्यांकन के साथ प्राप्त कोई अनुमान सशर्त असाइनमेंट या मूल्यांकन के साथ भी व्यावहारिक होना चाहिए। इसके अलावा यदि एक ऑपरेटर संदिग्ध है, तो दूसरे की धारणा संभावित रूप से अस्पष्टता को हल कर सकती है। अगर अस्पष्टता को हल नहीं किया जा सकता है तो संकलक अभी भी शिकायत कर सकता है क्योंकि यह उपर्युक्त उदाहरण में करता है। शायद एक छोड़ी गई सुविधा ...? – GDS

6

सी # कंपाइलर बनाया गया लैम्ब्डा अभिव्यक्ति के प्रकार का अनुमान नहीं लगा सकता है क्योंकि यह पहले टर्नरी को संसाधित करता है और फिर असाइनमेंट करता है। आप भी कर सकता है:

Func<Order, bool> predicate = 
    id == null ? 
     new Func<Order,bool>(p => p.EmployeeID == null) : 
     new Func<Order,bool>(p => p.EmployeeID == id); 

लेकिन है कि बस, बेकार आप भी आजमा सकते हैं

Func<Order, bool> predicate = 
    id == null ? 
     (Order p) => p.EmployeeID == null : 
     (Order p) => p.EmployeeID == id; 
+2

उत्तरार्द्ध काम नहीं करता है, क्योंकि संकलक को पता नहीं है कि किसी प्रतिनिधि या अभिव्यक्ति वृक्ष में परिवर्तित करना है या (कहें, एक Func <ऑर्डर, ऑब्जेक्ट> जो ठीक भी होगा)। –

0

मुझे मेरे हाल उदाहरण के बाद से मैं एक ही समस्या थी, भी (आशा उदाहरण है कि के साथ करते हैं दूसरों के लिए सहायक बनें):

मेरा Find विधि सामान्य विधि है जो Expression<Func<T, bool>> को भविष्यवाणी के रूप में प्राप्त करती है और List<T> आउटपुट के रूप में देती है।
मैं देशों को ढूंढना चाहता था, लेकिन अगर भाषा सूची खाली थी, और फ़िल्टर सूची भरने पर फ़िल्टर की गई सूची में मुझे उन सभी की ज़रूरत है। सबसे पहले मैं नीचे के रूप में कोड का प्रयोग किया:

var countries= 
Find(languages.Any() 
    ? (country => languages.Contains(country.Language)) 
    : (country => true)); 

लेकिन वास्तव में मैं त्रुटि मिलती है: there is no implicit conversion between lambda expression and lambda expression.

समस्या यह है कि, हम सिर्फ दो लैम्ब्डा भाव यहाँ, और कुछ नहीं है था, उदाहरण के लिए, क्या है country => true बिल्कुल ?? हमें का प्रकार कम से कम एक लैम्ब्डा अभिव्यक्ति निर्धारित करना है। यदि अभिव्यक्तियों में से केवल एक निर्धारित किया गया है, तो त्रुटि छोड़ी जाएगी। लेकिन कोड अधिक पठनीय बनाने के लिए, मैं दोनों लैम्ब्डा भाव निकाला, और बदले चर इस्तेमाल किया, जैसा कि नीचे:

Expression<Func<Country, bool>> getAllPredicate = country => true; 
    Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language); 

    var countries= Find(languages.Any() 
         ? getCountriesByLanguagePredicate 
         : getAllPredicate); 

मैं जोर देना है कि, अगर मैं सिर्फ अभिव्यक्ति के प्रकार में से एक निर्धारित किया है, त्रुटि को ठीक कर दिया जाएगा।

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