2009-10-20 18 views
21

मैं निम्नलिखित हस्ताक्षर के साथ एक विधि है स्वीकार करता लिखें:एक तरीका है जिसके एक लैम्ब्डा अभिव्यक्ति

"Cannot convert lambda expression to type 'object' because it is not a delegate type" 
:

MyMethod((int a) => a) 
निम्न त्रुटि के साथ

:

void MyMethod(Delegate d){}; 
void MyMethod(Expression exp){}; 
void MyMethod(object obj){}; 

बहरहाल, यह संकलन करने में विफल रहता है

यह क्यों काम नहीं करता है?

संपादित करें: मुझे पता है कि यह काम करता है। संकलक इस मामले में लैम्ब्डा अभिव्यक्ति को एक डिलीगेट में संकलित करता है।

void MyMethod(Func<int, int> d){}; 

सधन्यवाद,

+3

Fyi, जब भी कुछ संकलन करने में विफल रहता है, तो त्रुटि संदेश को भी पढ़ें (और पोस्ट करें)। –

+0

@SharePoint न्यूबी: कृपया मेरी अपडेट की गई पोस्ट देखें। इससे अब आपकी त्रुटि हल होनी चाहिए। – Noldorin

उत्तर

17

क्योंकि सिस्टम सिस्टम। डिलीगेट "प्रतिनिधि" नहीं है। यह सिर्फ आधार वर्ग है। आपको सही हस्ताक्षर के साथ एक प्रतिनिधि प्रकार का उपयोग करना होगा। अपने विधि को परिभाषित करें इस प्रकार है:

void MyMethod(Func<int, int> objFunc) 

संपादित करें:

MyMethod (वस्तु) क्योंकि एक लैम्ब्डा अभिव्यक्ति अपने आप में कोई प्रकार है, लेकिन प्रकार स्थान के प्रकार से अनुमान लगाया जाता है काम नहीं करता है यह को सौंपा गया है तो ऑब्जेक्ट या तो काम नहीं करता है। आपको सही हस्ताक्षर के साथ एक प्रतिनिधि प्रकार का उपयोग करना है।

+0

मुझे पता है कि यह काम करता है, मैं जानना चाहता हूं कि अन्य हस्ताक्षर क्यों काम नहीं करते हैं। –

+0

फिर मैंने जो लिखा है उसे पढ़ें। सिस्टम। डिलीगेट प्रतिनिधि नहीं है, लैम्ब्डा अभिव्यक्ति को सिस्टम में परिवर्तित नहीं किया जा सकता है। डिलीगेट। वास्तव में, लैम्ब्डा अभिव्यक्तियों का कोई प्रकार नहीं होता है, वे अपने प्रकार को वेरिएबल के प्रकार से प्राप्त करते हैं, इसलिए ऑब्जेक्ट या तो काम नहीं करता है। –

+0

लेकिन मैं खुद को टाइप कर रहा हूं। यह अनुमानित रूप से अनुमानित नहीं है, "(int a) => a;"। क्या आप कृपया समझा सकते हैं कि लैम्ब्डा अभिव्यक्तियों का कोई प्रकार नहीं है? –

12
void MyMethod(Action<int> lambdaHereLol) 
{ 
    lambdaHereLol(2); 
} 
उपयोग में

:

var hurrDurr = 5; 
MyMethod(x => Console.Write(x * hurrDurr)); 

सी # एक स्थिर टाइप किया भाषा है। कंपाइलर को यह सब कुछ पता होना चाहिए कि वह किस प्रकार से संबंधित है। Lambdas नीचे नाखून करने के लिए थोड़ा मुश्किल हैं, और कभी-कभी संकलक इसे समझ नहीं सकता है। उपरोक्त मेरे उदाहरण में, यदि MyMethod ने कोई ऑब्जेक्ट लिया है, तो संकलक यह नहीं समझ सका कि x एक int है (मेरा उदाहरण सरल है, लेकिन ऐसा कुछ भी नहीं है जो कहता है कि यह निर्धारित करने के लिए और अधिक जटिल और कठिन नहीं हो सकता है)। तो मुझे अपनी लैम्ब्डा लेने वाली विधि को परिभाषित करने में और अधिक स्पष्ट होना चाहिए।

+1

कोई और हमेशा "क्लोटर" और "बंद" मिश्रण करता है? – Will

+3

ट्रोल कोडर सेमेन्टिक्स के लिए +1 – Filip

+1

"सी # एक स्थैतिक टाइप की गई भाषा है। कंपाइलर को इसके साथ संबंधित सभी चीज़ों के प्रकार को जानने की आवश्यकता है।" यह सच है लेकिन बाकी का पालन नहीं करता है। वहां बहुत से स्थिर टाइप की गई भाषाएं हैं जो आपके लिए प्रकार के हस्ताक्षर का अनुमान लगा सकती हैं। एफ # एक उदाहरण है। – rgrinberg

2

इस प्रयास करें:

void MyMethod(Action<int> func) { } 

आप विधि के लिए एक पैरामीटर के रूप में एक जोरदार टाइप प्रतिनिधि की जरूरत है। अन्य कॉल विफल होने का कारण यह है कि सी # कंपाइलर आपको Object की अपेक्षा रखने वाली विधि में लैम्ब्डा अभिव्यक्ति को पारित करने की अनुमति नहीं देगा क्योंकि लैम्ब्डा अभिव्यक्ति हमेशा सभी मामलों में एक प्रतिनिधि नहीं होती है। यह वही नियम लैम्ब्डा अभिव्यक्ति को Delegate के रूप में पास करने के लिए लागू होता है।

जब आप लैम्ब्डा को किसी फ़ंक्शन में पास करते हैं जैसे मैंने ऊपर दिखाया है, तो संकलन सुरक्षित रूप से यह मान सकता है कि आप लैम्ब्डा अभिव्यक्ति को एक विशिष्ट प्रतिनिधि प्रकार में परिवर्तित करना चाहते हैं और ऐसा करते हैं।

+0

मुझे पता है कि यह काम करता है, मैं जानना चाहता हूं कि अन्य हस्ताक्षर क्यों काम नहीं करते हैं। –

0

यह केवल संकलक की प्रकृति है जिसे Delegate पर Delegate के पैरामीटर के रूप में पास करते समय आपको एक प्रतिनिधि ऑब्जेक्ट को स्पष्ट रूप से डालने की आवश्यकता है। वास्तव में, लैम्ब्डा अभिव्यक्तियों को और भी जटिल बनाते हैं कि वे इस मामले में प्रतिनिधियों के लिए पूरी तरह से परिवर्तनीय नहीं हैं।

MyMethod((Delegate)(Func<int, int>)((int a) => a)); 

जो निश्चित रूप से विधि हस्ताक्षर से मेल खाती है:

void MyMethod(Delegate d); 

अपनी स्थिति के आधार पर आप एक पैरामीटर परिभाषित करने के लिए चाहते हो सकता है

तुम क्या आवश्यकता होती है जैसे एक डबल डाली, है Delegate के बजाय टाइप करें (हालांकि मैं ओवरलोड जोड़ने में संकोच करूंगा, क्योंकि यह ईमानदारी में अनावश्यक जटिलता को जोड़ता है)।

+0

यह भी काम नहीं करता है। –

+0

हाँ, क्योंकि, जैसा कि मैंने लिखा है, सिस्टम। डिलीगेट प्रतिनिधि नहीं है। यह प्रतिनिधियों के लिए सिर्फ आधार प्रकार है। –

+1

वूप्स, आप सही हैं। मैंने एक प्रतिनिधि प्रकार के रूपांतरण को याद किया जिसे पहले होने की आवश्यकता है। इस प्रकार की अंतर्दृष्टि बताती है कि कैसे सी # कंपाइलर लैम्ब्डा अभिव्यक्तियों के प्रतिनिधि को निहित करता है, और फिर इसे पैरामीटर के रूप में कैसे पास करता है। आप यहां जो कुछ भी देखते हैं वह सब कुछ "मैन्युअल" कर रहा है। – Noldorin

3

(int a) => a जैसे लैम्ब्डा किसी भी प्रतिनिधि को फिट करेगा जो int लेता है और int देता है। Func<int,int> केवल एक उदाहरण है, और आप आसानी से delegate int Foo(int x); के साथ खुद को घोषित कर सकते हैं। वास्तव में यह लैम्ब्डा अभिव्यक्ति एक प्रतिनिधि को भी फिट करेगी जो int लेती है और double लौटाती है, क्योंकि लैम्ब्डा (a) का परिणाम double पर स्पष्ट रूप से परिवर्तनीय है।

लैम्ब्डा को सभी प्रतिनिधि प्रकारों के लिए असाइन करने योग्य होने के लिए, यह लैम्बडा स्वयं स्वाभाविक रूप से एक प्रकार नहीं है। इसके बजाए यह उस प्रतिनिधि के प्रकार को लेता है जिसका आप इसका उपयोग कर रहे हैं, जब तक यह संभव हो। ((int a) => a निश्चित रूप से Func<byte, byte> करने के लिए आवंटित नहीं किया जा सकता।)

जबकि दोनों Func<int, int> और Foo प्रतिनिधि मैं परिभाषित निश्चित रूप से कर सकते हैं Delegate लिए परिवर्तित किया जा, एक लैम्ब्डा सीधे Delegate में परिवर्तित नहीं किया जा सकता क्योंकि यह स्पष्ट नहीं है क्या इसकी वास्तविक तब हस्ताक्षर होगा। Delegate d = (int a) => a के बाद, dFoo, या Func<int, int>, या यहां तक ​​कि Func<int, double>? सभी मान्य संभावनाएं हैं, और संकलक को पता नहीं है कि आप क्या चाहते हैं। यह सबसे अच्छा अनुमान लगा सकता है, लेकिन सी # ऐसी भाषा नहीं है जो उस तरह का अनुमान लगाती है। यही कारण है कि आप var = (int a) => a जैसे कुछ नहीं कर सकते हैं।

मुझे लगता है कि त्रुटि संदेश संकलक Delegate d = (int a) => a; के लिए देता है करना बहुत स्पष्ट नहीं है:

Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type

Intuitively आपको लगता होगा Delegate एक प्रतिनिधि प्रकार है, लेकिन है कि कैसे चीजें काम नहीं है। :)

0

कारण विफल होने का कारण "ऑब्जेक्ट डेल = (int a) => a" या यहां तक ​​कि "var del = (int a) =>" विफल रहता है। आप सोच सकते हैं कि संकलक आपकी लैम्ब्डा अभिव्यक्ति के प्रकार को समझ सकता है क्योंकि आप स्पष्ट रूप से तर्क का प्रकार देते हैं, लेकिन यह भी जानते हुए कि अभिव्यक्ति एक int लेती है और एक int लौटाती है, ऐसे कई प्रतिनिधि प्रकार हैं जिन्हें इसे परिवर्तित किया जा सकता है सेवा मेरे। Func प्रतिनिधि प्रकार इस तरह के सामान्य कार्यों के लिए सबसे अधिक उपयोग किया जाता है, लेकिन यह सिर्फ एक सम्मेलन है और संकलक के बारे में कुछ भी पता नहीं है।

आपको कॉम्पलर को सामान्य कास्ट सिंटैक्स (Func) ((int a) => ए) का उपयोग करके, डिलीगेट ओवरलोड का चयन करने के लिए लैम्ब्डा अभिव्यक्ति को एक ठोस प्रतिनिधि प्रकार में डालने की आवश्यकता है, या प्रतिनिधि कन्स्ट्रक्टर सिंटैक्स का उपयोग कर नया Func ((int a) => ए)।

इसके अलावा, आप आमतौर पर अनियमित प्रतिनिधि वर्ग का उपयोग नहीं करना चाहते हैं जब तक कि आपको इसे स्वीकार किए जाने वाले तर्क की संख्या के आधार पर कुछ अलग करने की आवश्यकता न हो। कॉलबैक जैसी चीजों के लिए फनक या एक्शन स्वीकार करना लगभग हमेशा बेहतर होता है।

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