2013-02-19 70 views
5

[संपादित करें, पूरी तरह से दोहराया गया:] ऐसा लगता है कि मेरे प्रश्न की तरह वास्तव में खराब शब्द था, और खराब भी प्राप्त हुआ। तो मुझे आशा है कि यह पूरा rephrasing में मदद करता है ...सीएलआर-परिभाषित तरीकों जैसे [प्रतिनिधि] कहां हैं .बजिनइवोक दस्तावेज?

MSDN स्पष्ट रूप से बताता है कि निर्दिष्ट करता है: Control.BeginInvoke() धागा है कि नियंत्रण के हैंडल को बनाया गया था पर एक प्रतिनिधि कार्यान्वित करता है, आम तौर पर इस जीयूआई धागा होगा। और Dispatcher.BeginInvoke() थ्रेड पर चलाएगा जहां डिस्पैचर ऑब्जेक्ट बनाया गया था। यह मेरे द्वारा बनाई गई कोई धागा होगी।

लेकिन प्रतिनिधियों के लिए "CLR automatically defines BeginInvoke और EndInvoke" और ये कॉल इसके बजाय थ्रेडपूल-थ्रेड पर चलते हैं। इस आश्चर्यजनक भिन्न व्यवहार के अलावा मुझे आश्चर्य है कि मैं उन सभी कार्यों की चश्मा कैसे पा सकता हूं जो स्वचालित रूप से कार्यान्वित हो जाते हैं।

उदाहरण के लिए: इंटेलि-भावना से पता चलता है कि मेरे प्रतिनिधि के पास डायनामिक इनवोक() है। कक्षा System.Delegate{} में एक डायनामिक इनवोक() है जो दर्शा सकता है कि मेरे प्रतिनिधि को यह विरासत में मिला है। लेकिन प्रतिनिधि {} में कोई BeginInvoke() नहीं है। और प्रतिनिधि {} में कई कार्य हैं जो मेरे प्रतिनिधि नहीं हैं। इसके अलावा मेरे प्रतिनिधि को GetObjectData() विधि मिलती है। और यह ISerializable से आ रहा है।

तो निष्कर्ष में, एक प्रतिनिधि दिखाई देता है (1) सीएलआर "स्वचालित रूप से", (2) प्रतिनिधि के कुछ सबसेट {} संभवतः मल्टीकास्टडिलेगेट {}, और संभवतः (3) आईएसरियलज़बल। मुझे एक प्रतिनिधि को मिलने वाली सभी विधियों का व्यापक विनिर्देश कहां मिल सकता है? विशेष रूप से दिलचस्प है BeginInvoke(), और यह सटीक हस्ताक्षर, है क्योंकि उस नाम के दो उपरोक्त तरीकों के हस्ताक्षर के विभिन्न सेट हैं।

[किसी ने एक संपादन में सुझाव दिया कि "प्रतिनिधि" एक "प्रतिनिधि" है। मैं हिम्मत, ऐसा नहीं है।]

धन्यवाद

+1

एक ऐसे प्रश्न की तरह लगता है जो एमएसडीएन मंचों के लिए अधिक उपयुक्त है – chris

+1

क्या आपका प्रश्न है "माइक्रोसॉफ्ट के दस्तावेज क्यों चूसते हैं?" यदि ऐसा है, तो यह एक रान है। क्या कोई वास्तविक सवाल है? –

+2

आपके द्वारा उल्लेख किए गए एमएसडीएन आलेख में "थ्रेडपूल" के लिए खोजें। यह इसके बारे में काफी स्पष्ट है। –

उत्तर

21

Control.Begin/अंत/आह्वान() और Dispatcher.Begin/अंत/आह्वान() पद्धतियों के समान नाम और कुछ इसी तरह व्यवहार एक प्रतिनिधि के शुरू/अंत/आमंत्रण() विधियों पर विचार करें, लेकिन यह विचार करना सबसे अच्छा है कि वे समान हैं। सबसे महत्वपूर्ण अंतर यह है कि एक प्रतिनिधि के तरीके टाइप-सुरक्षित हैं, जो कि नियंत्रण और डिस्पैचर संस्करणों से पूरी तरह गायब है। रनटाइम व्यवहार भी बहुत अलग है।

एक प्रतिनिधि को नियंत्रित करने वाले नियमों को सीएलआई स्पेक, ECMA 335, अध्याय II.14.6 में विस्तार से बताया गया है। अध्याय को पढ़ना सबसे अच्छा है, मैं सिर्फ एक सारांश दूंगा।

एक प्रतिनिधि घोषणा एक वर्ग में परिवर्तित हो जाती है जो मल्टीकास्टडिलेगेट से प्राप्त होती है (सीएलआई स्पेक में उल्लिखित प्रतिनिधि नहीं)। यही कारण है कि वर्ग हमेशा की तरह, वास्तव में 4 सदस्य हैं उनके क्रम कार्यान्वयन CLR द्वारा प्रदान की जाती है:

  • एक निर्माता है कि एक वस्तु और एक IntPtr लेता है। ऑब्जेक्ट प्रतिनिधि है। लक्ष्य, IntPtr लक्ष्य विधि का पता है, Delegate.Method। जब आप प्रतिनिधि को आमंत्रित करते हैं तो इन सदस्यों का उपयोग बाद में किया जाता है, लक्ष्य संपत्ति को संदर्भ प्रदान करती है यदि प्रतिनिधि जिस सीमा को बाध्य करता है वह एक विधि विधि है, स्थिर विधि के लिए शून्य है। विधि संपत्ति निर्धारित करती है कि कौन सी विधि लागू की जाती है। आप इन तर्कों को सीधे निर्दिष्ट नहीं करते हैं, जब आप नए ऑपरेटर का उपयोग करते हैं या + = ऑपरेटर के साथ ईवेंट हैंडलर की सदस्यता लेते हैं तो संकलक उन्हें आपूर्ति करता है।घटनाओं के मामले में बहुत सी वाक्यविन्यास चीनी के साथ, आपको नया ऑपरेटर स्पष्ट रूप से उपयोग करने की आवश्यकता नहीं है।

  • एक आमंत्रण() विधि। विधि के तर्क गतिशील रूप से जेनरेट किए जाते हैं और प्रतिनिधि घोषणा से मेल खाते हैं। Invoke() विधि को कॉल करना उसी थ्रेड पर प्रतिनिधि लक्ष्य विधि चलाता है, तुल्यकालिक कॉल। आप इसे शायद ही कभी सी # में उपयोग करते हैं, आप सिंटैक्स चीनी का उपयोग करते हैं जो ऑब्जेक्ट नाम का उपयोग करके एक प्रतिनिधि ऑब्जेक्ट को आवेदक द्वारा अनुक्रमित करने की अनुमति देता है।

  • एक BeginInvoke() विधि, एसिंक्रोनस कॉल करने का एक तरीका प्रदान करता है। लक्ष्य विधि निष्पादित होने पर विधि पूर्ण हो जाती है, ThreadPool.QueueUserWorkItem के समान लेकिन टाइप-सुरक्षित तर्कों के साथ। रिटर्न प्रकार हमेशा System.IAsyncResult है, यह पता लगाने के लिए प्रयोग किया जाता है कि जब एसिंक्रोनस कॉल पूरा हो जाता है और EndInvoke() विधि को आपूर्ति की जाती है। पहला तर्क एक वैकल्पिक सिस्टम है। एसिंककॉलबैक प्रतिनिधि वस्तु, एसिंक्रोनस कॉल पूर्ण होने पर इसका लक्ष्य स्वचालित रूप से कॉल किया जाएगा। दूसरा तर्क एक वैकल्पिक ऑब्जेक्ट है, यह कॉलबैक के रूप में पारित किया जाएगा, जो राज्य का ट्रैक रखने के लिए उपयोगी है। अतिरिक्त तर्क गतिशील रूप से जेनरेट किए जाते हैं और प्रतिनिधि घोषणा से मेल खाते हैं।

  • एक एंड इनवोक() विधि। यह IAsyncResult प्रकार का एक भी तर्क लेता है, आपको BeginInvoke() से प्राप्त एक को पास करना होगा। यह एसिंक्रोनस कॉल को पूरा करता है और संसाधनों को रिलीज़ करता है।

किसी भी अतिरिक्त तरीकों आप एक प्रतिनिधि वस्तु पर देख जो कि आधार वर्ग, MulticastDelegate और प्रतिनिधि से विरासत में मिला रहे हैं। डायनामिक इनवोक() और GetObjectData() की तरह।

असिंक्रोनस कॉल मुश्किल हैं और आपको शायद ही कभी उनका उपयोग करने की आवश्यकता है। वे वास्तव में सिल्वरलाइट जैसे .NETCore लक्ष्यों में उपलब्ध नहीं हैं। प्रतिनिधि लक्ष्य विधि एक मनमाना थ्रेड-पूल धागे पर चलती है, जैसे थ्रेडपूल। क्यूयूयूसर वर्कइटम() करता है। किसी भी अनचाहे अपवाद को फेंक दिया जा सकता है और थ्रेड को समाप्त कर देता है लेकिन आपका प्रोग्राम नहीं। आप कॉल EndInvoke(), ऐसा नहीं कर रहे हैं 10 मिनट के लिए संसाधन रिसाव का कारण बन जाएगा। यदि लक्ष्य विधि ने अपवाद फेंक दिया है तो आप EndInvoke() को कॉल करते समय फिर से उठाए जाएंगे। थ्रेड-पूल थ्रेड पर आपका कोई नियंत्रण नहीं है, इसे रद्द करने या रद्द करने का कोई तरीका नहीं है। कार्य या थ्रेड कक्षाएं बेहतर विकल्प हैं।

एमएसडीएन प्रासंगिक है, एक प्रतिनिधि प्रकार के तरीके दस्तावेज नहीं हैं। यह आपको लगता है कि वे क्या करते हैं और वे विनिर्देश और प्रतिनिधि घोषणा से क्या दिखते हैं।

+0

एक उत्कृष्ट उत्तर के लिए धन्यवाद। वह सीएलआई-सामान एक सोने की खान है। – Adam

+0

एफडब्ल्यूआईडब्ल्यू, मैं इस बयान से असहमत हूं कि _ "एक प्रतिनिधि प्रकार के तरीके दस्तावेज नहीं हैं" _। यही है, जबकि प्रत्येक विशिष्ट प्रतिनिधि प्रकार में दस्तावेज़ीकरण नहीं होता है, एमएसडीएन में सामान्य दस्तावेज शामिल होता है जो वर्णन करता है कि ये विधियां वास्तव में क्या करती हैं। उदाहरण देखें https://msdn.microsoft.com/en-us/library/22t547yb(v=vs.110).aspx और https://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110) .aspx –

+0

Google, "methodinvoker.begininvoke" कहें। पहली एमएसडीएन हिट Control.BeginInvoke के लिए है। QED। –

8

आपके प्रश्न के विषय के अनुसार उत्तर इन बोल्ड लाइनों होगा। एमएसडीएन बेहतर नहीं हो सकता है लेकिन यह अच्छा है :)

जेफरी रिचटर ने ऊपर दिए गए आपके प्रश्न में जो कुछ पूछा है उसके बारे में लिखा है। उनके पास एमएसडीएन पत्रिका पर यह आलेख है। http://msdn.microsoft.com/en-us/magazine/cc164139.aspx यह आलेख आपको इस क्रियान्वयन को दिखाएगा कि वास्तव में (वास्तव में वास्तव में नहीं हो सकता है) इस BeginInvoke और EndInvoke वास्तव में .NET CLR में लागू किया गया है। इस लेख में कुछ समय निवेश करें और उसके बाद मुझे नहीं लगता कि अब आपको आगे पढ़ने की जरूरत है। जेफरी समृद्ध ने भी अपनी पुस्तक सीएलआर वाया सी # में यह सब अच्छी तरह से समझाया है।

अधिकांश यूआई अनुप्रयोग सिंगल थ्रेडेड हैं। यूआई पर नियंत्रण केवल उस धागे का उपयोग करके किया जा सकता है जिसके साथ वे बनाए गए थे।

इस नियंत्रण को स्वीकार करने के लिए। Winvs में इन्वोक मौजूद है। यह यूआई थ्रेड पर स्वचालित रूप से आपके कोड का आह्वान करेगा। डब्ल्यूपीएफ दुनिया में, हमारे पास Control.Invoke नहीं है। डब्ल्यूपीएफ में, हमारे पास नियंत्रण के बजाय डिस्पैचर है।

अब प्रतिनिधि बनाम प्रतिनिधि। हंस पासेंट ने एक बहुत अच्छा जवाब प्रदान किया है।

तो इसमें थोड़ा सा रहने के लिए, मैं यह जवाब लिख रहा हूं।

एमएसडीएन पर उल्लिखित प्रतिनिधि एक वर्ग है। इस कोड (MSDN http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx से लिया)

public delegate int PerformCalculation(int x, int y); 

ले आप यहाँ देख सकते हैं हम प्रतिनिधि (एक छोटे से 'प' के साथ ध्यान दें) है देता है। यह एक प्रतिनिधि को परिभाषित करने या इसे सरल शब्दों में रखने के लिए एक कीवर्ड है, यह एक वैरिएबल परफॉर्म्यूलेशन को परिभाषित करने वाला एक कीवर्ड है जिसमें वास्तव में किसी विधि का संदर्भ होता है।

मुझे लगता है कि आप पहले से ही इसके बारे में जानते हैं, लेकिन केवल पूर्णता के लिए।

अब इस चर का उपयोग और एक विधि इस तरह कोड का उपयोग कर को लागू करने की:

using System; 
// Declare delegate -- defines required signature: 
delegate void SampleDelegate(string message); 

class TestDelegate 
{ 
    private void CallMeUsingDelegate(string m_param) 
    { 
     Console.WriteLine("Called me using parameter - " + m_param); 
    } 

    public static void Main(string[] args) 
    { 
     // Here is the Code that uses the delegate defined above. 
     SampleDelegate sd = new SampleDelegate(CallMeUsingDelegate); 
     sd.Invoke("FromMain"); 
    } 
} 

अब एक विधि आप ऊपर CallMeUsingDelegate पद्धति के रूप में एक पूर्ण विधि लिखने की ज़रूरत आह्वान करने के लिए। सी # में यह अज्ञात विधियां है जिसका उपयोग किसी विधि को वास्तव में विधि के रूप में लिखने के बिना करने के लिए किया जा सकता है।

तो उपरोक्त कोड भी

प्रणाली का उपयोग कर के रूप में लिखा जा सकता है; // प्रतिनिधि घोषित करें - आवश्यक हस्ताक्षर परिभाषित करता है: प्रतिनिधि शून्य नमूना डिलीगेट (स्ट्रिंग संदेश);

class TestDelegate 
{ 
    public static void Main(string[] args) 
    { 
     // Here is the Code that uses the delegate defined above. 
     SampleDelegate sd = delegate(param) { 
         Console.WriteLine("Called me using parameter - " + param); 
        }; 

     sd.Invoke("FromMain"); 
    } 
} 

यह उपरोक्त कोड के समान काम करता है। लेकिन अब हमें कुछ कम कोड लिखने की जरूरत है। कंपाइलर उपरोक्त दोनों संस्करणों के लिए समान आईएल कोड बनाएगा। लेकिन 2 मामले में, नई विधि में कंपाइलर द्वारा स्वत: उत्पन्न नाम होगा।

जब BeginInvoke और EndInvoke की बात आती है, तो उनका उपयोग अतुल्यकालिक तरीके से करने के लिए किया जाता है। यह थ्रेडपूल का उपयोग करके किया जाता है जो सीएलआर के साथ उपलब्ध है।

असल में क्या होता है जब आप एक विधि

IAsyncResult ar = sd.BeginInvoke(CallMeUsingDelegate, callMeOnCompletion, sd); 

यहाँ का उपयोग कर प्रतिनिधि विधि है कि आप लागू कर रहे हैं कहते हैं। क्या होगा कि आपके प्रोग्राम का थ्रेड BeginInvoke विधि को कॉल करेगा जो आंतरिक रूप से सीएलआर थ्रेडपूल थ्रेड पर प्रतिनिधि पैरामीटर में निर्दिष्ट विधि का आह्वान करेगा। फिर आप प्रोग्राम जारी रखते रहेंगे और एक ऑब्जेक्ट लौटाएंगे जो IAsyncResult इंटरफ़ेस लागू करता है। आप इस ऑब्जेक्ट का उपयोग अपने प्रतिनिधि का उपयोग करके किए गए कार्य की प्रगति के बारे में पूछने के लिए कर सकते हैं (प्रतिनिधि पैरामीटर को 3 पैरामीटर के रूप में पारित करें)।

CallMeUsingDelegate विधि को एक अलग धागे (थ्रेडपूल के) पर बुलाया जाता है। जब कार्य पूरा हो जाएगा, थ्रेडपूल कॉलबैक विधि को 2 पैरामीटर के रूप में निर्दिष्ट करेगा।

यह सब देखकर आप सोच सकते हैं, हमें एंडइवोक की आवश्यकता क्यों है ???

वैसे ऐसा इसलिए है क्योंकि यदि आप एंडइवोक को कॉल नहीं करते हैं, तो सीएलआर थ्रेडपूल इस ऑपरेशन का संदर्भ रखेगा और आप कुछ स्मृति को रिसाव करेंगे। तो निर्दिष्ट कॉलबैक विधि में EndInvoke को कॉल करने के लिए यह हमेशा एक अच्छा अभ्यास है।

मुझे आशा है कि यह अब साफ़ हो जाएगा (सभी नहीं) लेकिन कुछ विचार।

+1

इस अतिरिक्त जानकारी के लिए धन्यवाद। रिक्टर हमेशा के रूप में, एक बहुत अच्छा लेखक है। – Adam