संकलन ठीक क्यों है, जब मैं इन्वोक विधि का उपयोग करता हूं, और ठीक नहीं जब मैं फंक को वापस लेता हूं <int, int> सीधे?


28

मैं इस मामले को नहीं समझता:

public delegate int test(int i);

public test Success()
{
    Func<int, int> f = x => x;
    return f.Invoke; // <- code successfully compiled 
}

public test Fail()
{
    Func<int, int> f = x => x;
    return f; // <- code doesn't compile
}

Invokeजब मैं csharp Func<int,int>सीधे वापस लौटता हूं तो मैं संकलन का उपयोग क्यों करता हूं, ठीक है ?


आपके पास एक प्रतिनिधि है जिसका अर्थ है कि आप किसी प्रकार का आयोजन कर रहे हैं। इनवोक क्रॉस-थ्रेड अपवाद को रोकता है और ऑब्जेक्ट को एक्सेस करने के लिए कई प्रक्रियाओं की अनुमति देता है।
jdweng

ध्यान दें कि आप इस मुद्दे को तब भी देखेंगे जब आप दो समान प्रतीत होने वाले प्रतिनिधियों का उपयोग करेंगे जैसे delegate void test1(int i);औरdelegate void test2(int i);
मैथ्यू वाटसन

जवाबों:


27

इस व्यवहार को समझने के लिए आपको दो बातें जानने की जरूरत है।

  1. सभी प्रतिनिधि से निकलते हैं System.Delegate, लेकिन विभिन्न प्रतिनिधियों के अलग-अलग प्रकार होते हैं और इसलिए उन्हें एक-दूसरे को नहीं सौंपा जा सकता है।
  2. सी # भाषा एक प्रतिनिधि को एक विधि या लैम्ब्डा निर्दिष्ट करने के लिए विशेष हैंडलिंग प्रदान करती है

क्योंकि अलग-अलग प्रतिनिधियों के अलग-अलग प्रकार होते हैं, इसका मतलब है कि आप एक प्रकार के प्रतिनिधि को दूसरे को नहीं सौंप सकते हैं।

उदाहरण के लिए, दिया गया:

delegate void test1(int i);
delegate void test2(int i);

फिर:

test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a;                 // Using normal assignment, therefore does not compile.

उपरोक्त पहली पंक्ति ओके को संकलित करती है क्योंकि यह लैम्बडा या किसी प्रतिनिधि को एक विधि निर्दिष्ट करने के लिए विशेष हैंडलिंग का उपयोग कर रही है।

वास्तव में, यह लाइन संकलक द्वारा इस तरह से फिर से लिखी गई है:

test1 a = new test1(Console.WriteLine);

ऊपर की दूसरी पंक्ति संकलित नहीं करती है क्योंकि यह एक प्रकार के उदाहरण को दूसरे असंगत प्रकार के रूप में निर्दिष्ट करने का प्रयास कर रही है।

जहाँ तक प्रकारों में जाते हैं, वहाँ कोई संगत कार्य नहीं होता है test1और test2क्योंकि वे विभिन्न प्रकार के होते हैं।

यदि इसके बारे में सोचने में मदद मिलती है, तो इस वर्ग पदानुक्रम पर विचार करें:

class Base
{
}

class Test1 : Base
{
}

class Test2 : Base
{
}

निम्नलिखित कोड संकलन नहीं करेगा, भले ही Test1और Test2उसी आधार वर्ग से प्राप्त हो:

Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.

यह बताता है कि आप एक प्रतिनिधि प्रकार को दूसरे को क्यों नहीं सौंप सकते हैं। वह सामान्य सी # भाषा है।

हालाँकि, महत्वपूर्ण बात यह समझना है कि आपको एक विधि या लैम्बडा को एक संगत प्रतिनिधि को सौंपने की अनुमति क्यों है। जैसा कि ऊपर उल्लेख किया गया है, यह प्रतिनिधियों के लिए C # भाषा समर्थन का हिस्सा है।

तो अंत में अपने प्रश्न का उत्तर दें:

जब आप उपयोग Invoke()करते हैं, तो आप एक असंगत प्रकार को निर्दिष्ट करने की कोशिश करने के बजाय एक प्रतिनिधि को विधियों या लैम्ब्डा निर्दिष्ट करने के लिए विशेष C # भाषा हैंडलिंग का उपयोग करके प्रतिनिधि को एक METHOD कॉल प्रदान कर रहे हैं - इसलिए यह ठीक संकलित करता है।

पूरी तरह से स्पष्ट होने के लिए, कोड जो आपके ओपी में संकलित है:

public test Success()
{
    Func<int, int> f = x => x;
    return f.Invoke; // <- code successfully compiled 
}

वास्तव में वैचारिक रूप से कुछ इस तरह से परिवर्तित किया जाता है:

public test Success()
{
    Func<int, int> f = x => x;
    return new test(f.Invoke);
}

जबकि असफल कोड दो असंगत प्रकारों के बीच असाइन करने का प्रयास कर रहा है:

public test Fail()
{
    Func<int, int> f = x => x;
    return f; // Attempting to assign one delegate type to another: Fails
}

6

दूसरे मामले में, fप्रकार का है Func<int, int>, लेकिन कहा जाता है कि विधि वापस आ जाएगी test। ये असंबंधित (डेलिगेट) प्रकार के होते हैं, जो एक दूसरे के लिए अपरिवर्तनीय होते हैं, इसलिए एक कंपाइलर त्रुटि होती है। आप भाषा कल्पना के इस भाग में जा सकते हैं , और "प्रतिनिधि" के लिए खोज कर सकते हैं । आपको उन प्रतिनिधियों के बीच रूपांतरण का कोई उल्लेख नहीं मिलेगा जिनके हस्ताक्षर समान हैं।

हालांकि पहले मामले में, f.Invokeएक विधि समूह अभिव्यक्ति है , जिसमें वास्तव में एक प्रकार नहीं है। C # संकलक विधि समूह अभिव्यक्तियों को विधि समूह रूपांतरण के माध्यम से संदर्भ के अनुसार विशिष्ट प्रतिनिधि प्रकार में बदल देगा ।

( यहां 5 वीं बुलेट का हवाला देते हुए , जोर दें)

एक अभिव्यक्ति को निम्न में से एक के रूप में वर्गीकृत किया गया है:

  • ...

  • एक विधि समूह, जो सदस्य लुकअप के परिणामस्वरूप अतिभारित विधियों का एक समूह है। [...] एक विधि समूह को एक आह्वान_प्रक्रिया में अनुमति दी जाती है, एक प्रतिनिधि_कारण_उपकरण और एक isऑपरेटर के बाएं हाथ के रूप में , और इसे एक संगत प्रतिनिधि प्रकार में परिवर्तित किया जा सकता है।

इस मामले में, इसे testप्रतिनिधि प्रकार में बदल दिया जाता है ।

दूसरे शब्दों में, return fकाम नहीं करता क्योंकि fपहले से ही एक प्रकार है, लेकिन f.Invokeअभी तक एक प्रकार नहीं है।


2

यहां जारी समस्या टाइप संगतता है:

MSDN स्रोतों से फ़ंक प्रतिनिधि की परिभाषा निम्नलिखित है :

public delegate TResult Func<in T, out TResult>(T arg);

यदि आप देखते हैं कि ऊपर उल्लिखित फंक और आपके परिभाषित प्रतिनिधि के बीच कोई सीधा संबंध नहीं है:

public delegate int test(int i);

क्यों 1 स्निपेट संकलन:

public test Success()
{
    Func<int, int> f = x => x;
    return f.Invoke; // <- code successfully compiled 
 }

डेलिगेट्स की तुलना सिग्नेचर के उपयोग से की जाती है, जो इनपुट पैरामीटर्स और आउटपुट परिणाम है, अंततः एक डेलिगेट एक फंक्शन पॉइंटर है और दो कार्यों की तुलना केवल हस्ताक्षर के माध्यम से की जा सकती है। रनटाइम के दौरान फंक के जरिए लगाई गई विधि Testप्रतिनिधि को सौंपी जाती है, क्योंकि सिग्नेचर एक ही है यह मूल रूप से काम करता है। यह एक फंक्शन पॉइंटर असाइनमेंट है, जहां Testडेलीगेट अब फंक डेलीगेट द्वारा बताई गई विधि को लागू करेंगे

क्यों दूसरा स्निपेट संकलन में विफल रहता है

फंक और टेस्ट प्रतिनिधि के बीच, कोई प्रकार / असाइनमेंट संगतता नहीं है, फंक टाइप सिस्टम नियमों के भाग के रूप में नहीं भर सकता है। यहां तक ​​कि जब इसका परिणाम सौंपा जा सकता है और test delegateपहले मामले में किया जा सकता है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.