2009-09-20 14 views
52

मैं अपने स्वयं के तरीकों से .NET या ASP MVC फ्रेमवर्क में शामिल एक्सटेंशन विधियों को प्रतिस्थापित करना चाहता हूं।मौजूदा एक्सटेंशन विधि को ओवरराइड करने के लिए कैसे करें

उदाहरण

public static string TextBox(this HtmlHelper htmlHelper, string name) 
{ 
    ... 
} 

क्या यह संभव है? मैं ओवरराइड या नए कीवर्ड का उपयोग नहीं कर सकता।

उत्तर

93

अद्यतन: यह प्रश्न the subject of my blog in December of 2013 था। महान सवाल के लिए धन्यवाद!


आप इसे एक अर्थ में कर सकते हैं। लेकिन मुझे सी # में ओवरलोड रिज़ॉल्यूशन के बुनियादी डिजाइन सिद्धांत के बारे में संक्षेप में बात करके शुरू करना चाहिए। सभी अधिभार संकल्प, निश्चित रूप से, एक ही नाम के साथ विधियों का एक सेट लेने और उस सेट से चुनने के लिए अद्वितीय सर्वश्रेष्ठ सदस्य कॉल करने के बारे में है।

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

और इसलिए हम सूची को चलाते हैं। व्युत्पन्न कक्षाएं बेस कक्षाओं के करीब हैं। आंतरिक वर्ग बाहरी वर्गों के करीब हैं। कक्षा पदानुक्रम में तरीके विस्तार विधियों के करीब हैं।

और अब हम आपके प्रश्न पर आते हैं।एक विस्तार विधि का निकटता इस पर निर्भर करता है (1) हमें कितने नामस्थान "बाहर" जाना है? और (2) क्या हमें using के माध्यम से एक्सटेंशन विधि मिल गई थी या क्या यह नामस्थान में ठीक था? इसलिए आप कॉल स्टेट पर एक करीबी नेमस्पेस में रखने के लिए, अपनी स्थाई विस्तार कक्षा किस नामस्थान में बदलकर ओवरलोड रिज़ॉल्यूशन को प्रभावित कर सकते हैं। या, आप using घोषणाओं को नामस्थान के using को रखने के लिए बदल सकते हैं जिसमें वांछित स्थैतिक वर्ग दूसरे के करीब है।

उदाहरण के लिए, यदि आप

namespace FrobCo.Blorble 
{ 
    using BazCo.TheirExtensionNamespace; 
    using FrobCo.MyExtensionNamespace; 
    ... some extension method call 
} 

है तो यह जो करीब है अस्पष्ट है। Blorple में कक्षाएं पहले जाना हो जब अधिभार संकल्प विस्तार विधि कॉल को हल करने के लिए चला जाता

namespace FrobCo 
{ 
    using BazCo.TheirExtensionNamespace; 
    namespace Blorble 
    { 
    using FrobCo.MyExtensionNamespace; 
    ... some extension method call 
    } 

और अब, है, तो FrobCo.MyExtensionNamespace में कक्षाएं, तो कक्षाएं: आप उनकी अधिक तुम्हारा प्राथमिकता देने के लिए चाहते हैं, आप ऐसा करने के लिए चुन सकते हैं FrobCo में, और फिर BazCo.TheirExtensionNamespace में कक्षाएं।

क्या यह स्पष्ट है?

+0

यहां एक प्रश्न, मैं कैसे कर सकता हूं मेरी कक्षा के लिए बनाए गए एक्सटेंशन विधि पर मेरी कक्षा विधि छुपाएं? जैसे क्लास हिरण के पास रन विधि है और मैं यह सुनिश्चित करना चाहता हूं कि जब मैं "मंगल" नेमस्पेस (क्लास मार्सलैण्ड) के अंदर हिरण का उपयोग करता हूं तो मैं यह सुनिश्चित करना चाहता हूं कि मंगल नेमस्पेस के विस्तार विधियों में घोषित रन विधि को कॉल किया जाएगा। हिरण नामस्थान पृथ्वी का हिस्सा है। – Dhananjay

+3

@ धनंजय: कक्षा पदानुक्रम के भीतर से एक लागू विधि * हमेशा * एक विस्तार विधि पर जीत जाती है। यदि आपको कॉल करने के लिए एक विस्तार विधि की आवश्यकता है, तो इसे एक स्थिर विधि के रूप में कॉल करें। –

+1

'FrobCo.MyExtensionNamespace' *' BazCo.irExtensionNamespace' की तुलना में 'FrobCo.Blorble' में किसी भी वर्ग के करीब क्यों नहीं है? मुझे लगता है कि BazCo-एक्सटेंशन के लिए आपको दो नामस्थान स्तरों और फिर दो अन्य लोगों के नीचे जाना होगा, जबकि FrobCo-एक्सटेंशन के लिए आपको केवल एक नामस्थान स्तर नीचे जाना होगा। इसलिए, मेरे लिए, FrobCo- एक्सटेंशन करीब लगते हैं। – Virtlink

26

विस्तार विधियों को ओवरराइड नहीं किया जा सकता क्योंकि वे उदाहरण विधियां नहीं हैं और वे वर्चुअल नहीं हैं।

अगर आप नाम स्थान के माध्यम से दोनों विस्तार विधि वर्गों आयात के रूप में यह पता नहीं होगा जो विधि कॉल करने के संकलक शिकायत:

कॉल निम्न विधियों या गुणों के बीच अस्पष्ट है: ...

इसके आसपास एकमात्र तरीका सामान्य स्थैतिक विधि वाक्यविन्यास का उपयोग करके अपनी विस्तार विधि को कॉल करना है। तो यह करने के बजाय:

a.Foo(); 

यदि आप ऐसा करने के लिए होता है:

YourExtensionMethodClass.Foo(a); 
+0

खैर के रूप में एरिक नोटों यह दो अलग-अलग मिलान विस्तार तरीकों का आयात नहीं कर रहा है, यह उनमें से एक ही स्तर पर आयात कर रहा है नेस्टिंग। और इम यकीन है कि वह एक के व्यवहार अधिभावी के बारे में बात कर रहा है एक अलग व्यवहार के व्यवहार के साथ विधि और बहुलक व्यवहार के बारे में नहीं –

4

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

लेकिन कैसे के बारे में उदाहरण के तरीकों विस्तार तरीकों पर पूर्वता है मैट Manela वार्ता: विस्तार तरीकों के बारे में और उपायों के लिए http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/e42f1511-39e7-4fed-9e56-0cc19c00d33d

आप पर http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/

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

3

एरिक आधार (और तथ्य यह है कि कोड विचार एएसपी नेम स्पेस में प्रदान की गई है) आप इस तरह इसे ओवरराइड में सक्षम होना चाहिए के आधार पर (कम से कम यह ASP.NET MVC4.0 उस्तरा में

using System.Web.Mvc; 

namespace ASP { 
    public static class InputExtensionsOverride { 
    public static MvcHtmlString TextBox(this HtmlHelper htmlHelper, string name) { 
     TagBuilder tagBuilder = new TagBuilder("input"); 
     tagBuilder.Attributes.Add("type", "text"); 
     tagBuilder.Attributes.Add("name", name); 
     tagBuilder.Attributes.Add("crazy-override", "true"); 
     return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal)); 
    } 
    } 
} 
मेरे लिए काम करता

नोट नाम स्थान होने के लिए "एएसपी" है।

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