विस्तारित वर्ग के भीतर एक्सटेंशन पद्धति को कॉल करने के लिए 'यह' कीवर्ड क्यों आवश्यक है


79

मैंने ASP.NET MVC व्यूपेज के लिए एक एक्सटेंशन विधि बनाई है, जैसे:

public static class ViewExtensions
{
    public static string Method<T>(this ViewPage<T> page) where T : class
    {
        return "something";
    }
}

इस विधि को किसी दृश्य से कॉल करते समय (इससे प्राप्त ViewPage), मुझे " CS0103: त्रुटि" नाम वर्तमान संदर्भ में मौजूद नहीं है "जब तक कि मैं thisइसे कॉल करने के लिए कीवर्ड का उपयोग नहीं करता :

<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->

thisकीवर्ड की आवश्यकता क्यों है ? या यह इसके बिना काम करता है, लेकिन मुझे कुछ याद आ रहा है?

(मुझे लगता है कि इस सवाल का एक डुप्लिकेट होना चाहिए, लेकिन मुझे एक नहीं मिला)

अपडेट :

जैसा कि बेन रॉबिन्सन कहते हैं , विस्तार विधियों को कॉल करने के लिए वाक्यविन्यास सिर्फ संकलक चीनी है। फिर कंपाइलर इस कीवर्ड की आवश्यकता के बिना वर्तमान प्रकार के आधार प्रकारों के विस्तार के तरीकों की स्वचालित रूप से जांच क्यों नहीं कर सकता है?


@ M4N - यह आपके द्वारा किए गए संभावित डुप्लिकेट की तरह दिखता है: मैं क्लास में ऑर्डरबी को कॉल क्यों नहीं कर सकता जो सूची का विस्तार करता है?
djdd87

@GenericTypeTea: हाँ यह एक ऐसा ही सवाल है। लेकिन मैं यह नहीं पूछ रहा हूं कि एक्सटेंशन विधि कैसे कॉल करें (मुझे पता है कि मुझे thisकीवर्ड जोड़ना है ), लेकिन मैं पूछ रहा हूं कि thisकीवर्ड की आवश्यकता क्यों है। मैंने अपना प्रश्न अपडेट किया।
M4N

@ M4N - अच्छा बिंदु, वे कहते हैं कि यह किया जाना है, लेकिन जवाब वास्तव में क्यों के रूप में एक अच्छा पर्याप्त विवरण नहीं देते हैं।
djdd87

उदाहरण के तरीकों पर, 'यह' विधि के लिए निहित है । इस पद्धति के बजाय मेथड () को कॉल करके (मेथोड) या विधि (यह), आप कंपाइलर को यह नहीं बता रहे हैं कि विधि को क्या पास करना है।
एलेक्स हम्फ्री

@ एलेक्स। तकनीकी रूप से मैं कल्पना करता हूं कि कंपाइलर के लिए कॉलिंग मेथड () के संदर्भ में "यह" अनुमान लगाना संभव होगा, हालांकि मुझे लगता है कि यह एक खराब डिजाइन विकल्प होता और कोड को कम पठनीय बनाते।
बेन रॉबिन्सन

जवाबों:


55

कुछ बिंदु:

सबसे पहले, प्रस्तावित सुविधा (एक विस्तार विधि कॉल पर "यह निहित है") अनावश्यक है । LINQ क्वेरी समझ के लिए एक्सटेंशन तरीके आवश्यक थे जिस तरह से हम चाहते थे; रिसीवर को हमेशा क्वेरी में बताया जाता है, इसलिए LINQ काम करने के लिए इसे निहित समर्थन करने के लिए आवश्यक नहीं है।

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

यदि आप उस प्रकार के परिदृश्य में हैं जहां आप उस प्रकार के लिए एक एक्सटेंशन विधि का उपयोग कर रहे हैं तो आपके पास स्रोत कोड तक पहुंच है। आप पहली बार एक्सटेंशन पद्धति का उपयोग क्यों कर रहे हैं? यदि आप विस्तारित प्रकार के स्रोत कोड तक पहुंच रखते हैं, तो आप खुद एक इंस्टेंस विधि लिख सकते हैं और फिर आपको एक्सटेंशन विधि का उपयोग करने की आवश्यकता नहीं है! आपका कार्यान्वयन तब वस्तु की निजी स्थिति तक पहुंच का लाभ उठा सकता है, जो विस्तार विधियां नहीं कर सकती हैं।

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

उन दो बिंदुओं को देखते हुए, भाषा डिजाइनर पर बोझ यह बताने के लिए नहीं रह जाता है कि यह सुविधा मौजूद क्यों नहीं है। अब यह आप पर पड़ता है कि आपको यह क्यों समझाना चाहिए । सुविधाएँ उनके साथ जुड़े हुए हैं। यह सुविधा आवश्यक नहीं है और विस्तार विधियों के निर्दिष्ट डिजाइन लक्ष्यों के खिलाफ काम करती है; हमें इसे लागू करने की लागत क्यों लेनी चाहिए? बताएं कि इस विशेषता से कौन सा सम्मोहक, महत्वपूर्ण परिदृश्य सक्षम है और हम भविष्य में इसे लागू करने पर विचार करेंगे। मुझे ऐसा कोई सम्मोहक, महत्वपूर्ण परिदृश्य नहीं दिख रहा है जो इसे सही ठहराता हो, लेकिन शायद एक ऐसा है जिसे मैंने याद किया है।


11
उस उत्तर के लिए धन्यवाद! दो अंक: 1: मैं उस सुविधा को लागू करने के लिए नहीं कह रहा था, सिर्फ एक स्पष्टीकरण के लिए, यह क्यों नहीं है / क्यों thisआवश्यक है। 2: मैं विस्तारित प्रकार से एक्सटेंशन पद्धति क्यों कहता हूं? दिए गए उदाहरण में, मैं कुछ सुविधा विधियों को आधार वर्ग (ViewPage) में जोड़ रहा हूं और मैं इसे व्युत्पन्न कक्षाओं से बुला रहा हूं। यह मेरे सभी विचारों के लिए एक सामान्य आधार वर्ग बनाने की आवश्यकता को समाप्त करता है। BTW: मैं सहमत हूं कि विस्तारित प्रकार के भीतर से एक एक्सटेंशन विधि का उपयोग करना अजीब है, लेकिन फिर से एमवीसी व्यूपेज के साथ उदाहरण देखें।
15:

3
@ M4N: ठीक यही स्थिति मेरी भी है: मैं UserControl पद्धति का विस्तार करना चाहता हूं और उस विस्तार को मेरे सभी UserControls के पास उपलब्ध है, बिना स्पष्ट 'यह' के। मुझे पता है कि संकलक विकास एक लोकतंत्र नहीं है, लेकिन इस वोट के लिए मेरे वोट पर विचार करें 'यह' :-)
डंकन बायने

8
हाय एरिक, दी यह एक प्राथमिक परिदृश्य नहीं है। हालाँकि सामान्य पैटर्न लगता है 1. आपके पास बेस क्लास के लिए सोर्स-एडिट एक्सेस नहीं है। 2. आप आधार प्रकार के कुछ (संरक्षित) तरीके जोड़ना चाहते हैं, जिसे आप व्युत्पन्न वर्गों के निकायों के भीतर लागू करना चाहते हैं। क्या इसे प्राप्त करने के लिए कुछ अन्य तंत्र है? this.MethodName टाइप करना इतना कठिन नहीं है लेकिन थोड़ी देर बाद गुस्सा आ जाता है ...
Gishu

5
मुझे लगता है कि बेस क्लास (जिसके लिए आपके पास स्रोत नहीं है) के लिए एक एक्सटेंशन विधि जोड़ने का परिदृश्य एक मान्य है। उस मामले में "इस" के बिना विधि को कॉल करने में सक्षम होना अच्छा होगा। BTW यह "स्थैतिक आयात" के साथ अगले सी # संस्करण में हल किया जा सकता है।
लिसेर्जिक-एसिड

4
आप जिस कक्षा में विस्तार कर रहे हैं, उसके भीतर से एक्सटेंशन विधियों का उपयोग करने का एक वैध कारण यह है कि आपके पास एक इंटरफ़ेस लागू करने वाले कई प्रकार हैं। उदाहरण के लिए, आपके पास दो कक्षाएं हैं जो लागू होती हैं ICrossProductable, और आप उस इंटरफ़ेस पर एक विस्तार विधि को परिभाषित करते हैं GetProduct। बहुत सरल उदाहरण है, लेकिन मुझे अक्सर यह उपयोगी लगता है। यह सभी मामलों में सबसे अच्छा तरीका नहीं है।
इयान न्यूजन

9

इसके बिना संकलक इसे एक स्थिर वर्ग के रूप में एक स्थिर विधि के रूप में देखता है जो पहले पैरामीटर के रूप में पृष्ठ लेता है। अर्थात

// without 'this'
string s = ViewExtensions.Method(page);

बनाम

// with 'this'
string s = page.Method();

1
मुझे लगता है कि यह ViewExtensions.Method (पेज) माना जाता है।
डेव वान डेन आईंडी

6

उदाहरण के तरीकों पर, 'यह' प्रत्येक विधि को पारदर्शी रूप से पारित किया जाता है, इसलिए आप इसे प्रदान करने वाले सभी सदस्यों तक पहुंच सकते हैं।

विस्तार विधियाँ स्थिर हैं। इसके Method()बजाय कॉल करके this.Method()या Method(this), आप संकलक को यह नहीं बता रहे हैं कि विधि को क्या पास करना है।

आप कह सकते हैं कि 'यह क्यों महसूस नहीं होता है कि कॉलिंग ऑब्जेक्ट क्या है और इसे एक पैरामीटर के रूप में पास करें?'

इसका उत्तर यह है कि विस्तार विधियां स्थिर हैं और इन्हें स्थिर संदर्भ से बुलाया जा सकता है, जहां कोई 'यह' नहीं है।

मुझे लगता है कि वे संकलन के दौरान इसके लिए जांच कर सकते हैं, लेकिन ईमानदार होने के लिए, यह शायद बहुत कम भुगतान के लिए बहुत काम है। और ईमानदार होने के लिए, मुझे विस्तार विधि कॉल के कुछ गवाहों को दूर करने में बहुत कम लाभ दिखाई देता है। तथ्य यह है कि वे उदाहरण के तरीकों के लिए गलत हो सकते हैं, इसका मतलब है कि वे कई बार अनजाने में हो सकते हैं (NullReferenceException को उदाहरण के लिए नहीं फेंका जा रहा है)। मुझे कभी-कभी लगता है कि उन्हें विस्तार के तरीकों के लिए एक नया 'पाइप-फॉरवर्ड' स्टाइल ऑपरेटर पेश करना चाहिए था।


तो ऐसा लगता है कि वे वास्तव में एक बुरा डिजाइन विकल्प होने के कारण यह एक स्थिर संदर्भ से बुलाया जा करने में सक्षम होने के बाद, जैसा कि मैं नहीं देखता कि कोई भी क्यों होगा।
ऑस्टिनवेब्रियन

3

यह ध्यान रखना महत्वपूर्ण है कि विस्तार विधियों और नियमित तरीकों के बीच अंतर हैं। मुझे लगता है कि आप उनमें से एक भर में आए हैं।

मैं आपको एक और अंतर का एक उदाहरण दूंगा: एक nullवस्तु संदर्भ पर एक विस्तार विधि को कॉल करना काफी आसान है । सौभाग्य से, यह नियमित तरीकों के साथ करना अधिक कठिन है। (लेकिन यह किया जा सकता है। IIRC, जॉन स्कीट ने सीआईएल कोड में हेरफेर करके यह करने के लिए प्रदर्शन किया।)

static void ExtensionMethod(this object obj) { ... }

object nullObj = null;
nullObj.ExtensionMethod();  // will succeed without a NullReferenceException!

यह कहा जा रहा है, मैं मानता हूं कि यह थोड़ा सा लगता है कि thisविस्तार पद्धति को कॉल करना आवश्यक है। आखिरकार, एक विस्तार विधि को आदर्श रूप से "महसूस" करना चाहिए और सामान्य की तरह व्यवहार करना चाहिए।

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


Boo भाषा में आप null यानी null.Do () पर सीधे एक्सटेंशन मेथड या प्रॉपर्टी इनवॉइस कर सकते हैं।
सेर्गेई मीरवोडा

1
@Sergey: खतरनाक लगता है ... :) मुझे उत्सुक बनाता है कि बू कैसे (निहित) प्रकार जानता है null? किसी भी संदर्भ प्रकार के बारे में हो सकता है, यह कैसे पता चलता है कि कौन से तरीके उपलब्ध हैं null?
stakx - अब

1
अशक्त संदर्भ के साथ एक विस्तार विधि को कॉल करने में सक्षम होने का एक अच्छा कारण हो सकता है।
डेव वान डेन आईंडी

@DaveVandenEynde: IMHO, यह एक गलती के लिए था। यह गैर-आभासी तरीकों के लिए एक विशेषता को परिभाषित नहीं करने के लिए जरूरी है कि संकलक उन्हें गैर-आभासी कॉल के साथ आमंत्रित करें। कुछ अपरिवर्तनीय वर्ग प्रकार जैसे Stringतार्किक रूप से मूल्यों के रूप में व्यवहार करते हैं, और एक समझदार डिफ़ॉल्ट हो सकते हैं जब अशक्त (जैसे। नेट लगातार stringकेवल एक प्रकार का कार्य करने के बजाय एक स्थिर स्ट्रिंग के रूप में स्थैतिक प्रकार के एक शून्य संदर्भ का संबंध हो सकता है )। ऐसी चीज़ों के लिए स्थैतिक तरीकों का उपयोग if (!String.IsNullOrEmpty(stringVar))करना बस छिपाना है।
सुपरकैट

1
@ सुपरकैट हां, छुपा हुआ। आप string.IsNullOrEmpty () भी कर सकते हैं। बहुत प्रीतिकर।
डेव वान डेन आईंडी

1

क्योंकि एक्सटेंशन विधि ViewPage वर्ग के साथ मौजूद नहीं है। आपको संकलक को यह बताने की आवश्यकता है कि आप एक्सटेंशन विधि पर क्या कह रहे हैं। याद रखें this.Method()कि सिर्फ कंपाइलर शुगर है ViewExtensions.Method(this)। यह उसी तरह है जिस तरह से आप किसी विधि के नाम से किसी भी वर्ग के मध्य में एक्स्टेंशन विधि नहीं कह सकते।


1
यह (किसी तरह) समझ में आता है। लेकिन अगर यह कंपाइलर शुगर है, तो कंपाइलर बिना thisकीवर्ड के एक्सटेंशन के तरीकों की जांच क्यों नहीं कर सकता है ?
M4N

मुझ पर एक नजर की तरह लग रहा है। जैसा कि आपने कहा - संकलक देख सकता है कि विधि मौजूद नहीं है, फिर उपलब्धता के लिए एक्सटेंशन जांचें।
टॉमटॉम

हाँ यकीनन यह काम कर सकता है। मुझे संदेह है कि यह कोड को अधिक पठनीय बनाने के लिए एक विशिष्ट डिजाइन निर्णय है। यदि आप किसी श्रेणी में एक्सटेंशनमैथोड () को कॉल कर सकते हैं, तो यह कोड पढ़ने वाले किसी व्यक्ति के लिए थोड़ा भ्रमित हो सकता है यदि उस वर्ग में वह विधि नहीं है, लेकिन इस के साथ। एक्सटेन्शनमेथोड () कम से कम यह MyInstance.ExtentionMethod () का उपयोग करने के साथ संगत है
बेन रॉबिन्सन

मुझे लगता है कि यह। मीथोड () व्यूएक्स्टेंशन के लिए सिंटैक्टिक शुगर की तरह है। मेथोड (यह)।
एलेक्स हम्फ्री

1

मैं एक धाराप्रवाह एपीआई पर काम कर रहा हूं और उसी मुद्दे पर भाग रहा हूं। हालाँकि मैं जिस कक्षा में प्रवेश कर रहा हूँ, उसकी पहुँच मैं अभी भी चाहता हूँ कि प्रत्येक धाराप्रवाह पद्धति का तर्क उनकी अपनी फाइलों में हो। "यह" कीवर्ड बहुत ही अनपेक्षित था, उपयोगकर्ता यह सोचते थे कि विधि गायब है। मैंने जो किया वह मेरी कक्षा को एक आंशिक वर्ग बना दिया जिसने विस्तार विधियों का उपयोग करने के बजाय मेरी ज़रूरत के तरीकों को लागू किया। मैंने जवाबों में किसी भी तरह के धारावाहिक का उल्लेख नहीं देखा। यदि आपके पास यह प्रश्न है तो एक बेहतर विकल्प हो सकता है।

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