2013-04-22 7 views
6

तो मेरे पास एएसपीनेट एमवीसी में यूई नियंत्रण बनाने के लिए ऑब्जेक्ट पदानुक्रम है और एक धाराप्रवाह एपीआई प्राप्त करने का प्रयास करें। मैं वर्तमान समस्या पर ध्यान केंद्रित करने के लिए कुछ डमी वर्ग बनाते हैं।.NET में एक्सटेंशन विधियों को "ओवरराइड" कैसे करें?

public abstract class HtmlElement { /* ... */ } 

public abstract class UIElement : HtmlElement { /* ... */ } 

public abstract class ButtonBase : UIElement { /* ... */ } 

public class LinkButton : ButtonBase { /* ... */ } 

public class ActionButton : ButtonBase { /* ... */ } 


public static class HtmlElementExtensions 
{ 
    public static T Id<T>(this T item, string id) where T : HtmlElement 
    { 
    /* set the id */ 
    return item; 
    } 
} 

public static class ButtonBaseExtensions 
{ 
    public static T Id<T>(this T item, string id) where T : ButtonBase 
    { 
    /* set the id and do some button specific stuff*/ 
    return item; 
    } 
} 

जब मैं एक LinkButton पर ईद कॉल करने के लिए कोशिश संकलक का कहना है वहाँ अस्पष्ट कॉल है:

LinkButton lb = new LinkButton().Id("asd"); 

मैं वास्तव में है कि संकलक चुनें सोचा
तो यहाँ "गलत" codebase है इस मामले में सबसे नज़दीकी मैच इसलिए यदि मेरे पास स्क्रिप्ट क्लास है जो HtmlElement से HtmlExtensions आईडी विधि से प्राप्त होती है, और लिंकबटन (प्रतिबंधों के कारण) के लिए बटनबेज विधि कहा जाएगा। मेरे पास एक समाधान है, लेकिन मुझे यकीन नहीं है कि एक बेहतर है।
मैं ButtonBaseExtensions से ईद विधि हटा सकते हैं और HtmlElementExtensions क्रमांक विधि संशोधित निम्नलिखित तरीके के रूप में:

public static T Id<T>(this T item, string id) where T : HtmlElement 
{ 
    if (item is ButtonBase) 
    { 
    /* do some button specific stuff*/ 
    } 
    /* set the id */ 
    return item; 
} 

इस तरह ButtonBase से हर वर्ग वंशज काम कर रहा है। मुझे वास्तव में मेरा समाधान पसंद नहीं है क्योंकि यह बटनबेस तर्क के साथ HtmlElement तर्क को मिलाता है। बेहतर समाधान के लिए कोई विचार/सुझाव? मैंने सोचा कि मैंने उन्हें अलग-अलग नामस्थान में रखा है, लेकिन सिर्फ एक सेकंड के लिए। मुझे दोनों नामस्थान का उपयोग करना होगा, इसलिए समस्या का समाधान न करें।

क्या आपको लगता है कि एमएसडीएन मंचों पर उल्लेख करने के लायक है कि संकलक सामान्य विस्तार विधियों पर प्रतिबंध देखना चाहिए?

इस बीच में मैं कुछ और अधिक शोध करने के लिए और MSDN मंचों पर एक धागा शुरू: link
मैं कुछ गैर सामान्य विस्तार methodds की कोशिश की:

BaseClass bc = new BaseClass(); 
InheritedClass ic = new InheritedClass(); 
BaseClass ic_as_bc = new InheritedClass(); 

bc.SomeMethod("bc"); 
ic.SomeMethod("ic"); 
ic_as_bc.SomeMethod("ic_as_bc"); 
:

public class BaseClass { /*...*/ } 
    public class InheritedClass : BaseClass { /*...*/ } 

    public static class BaseClassExtensions 
    { 
    public static void SomeMethod(this BaseClass item, string someParameter) 
    { 
     Console.WriteLine(string.Format("BaseClassExtensions.SomeMethod called wtih parameter: {0}", someParameter)); 
    } 
    } 

    public static class InheritedClassExtensions 
    { 
    public static void SomeMethod(this InheritedClass item, string someParameter) 
    { 
     Console.WriteLine(string.Format("InheritedClassExtensions.SomeMethod called wtih parameter: {0}", someParameter)); 
    } 
    } 

और अगर मैं इन का दृष्टांत

इस आउटपुट का उत्पादन:

BaseClassExtensions.SomeMethod called wtih parameter: bc 
InheritedClassExtensions.SomeMethod called wtih parameter: ic 
BaseClassExtensions.SomeMethod called wtih parameter: ic_as_bc 

You can vote it for now

धन्यवाद,
Péter

+1

एक विस्तार विधि है ** नहीं ** एक आभासी विधि के लिए एक विकल्प, न ही यह आभासी बनाया जा सकता है। यह बिल्कुल अस्पष्ट है कि आपको एक की आवश्यकता क्यों है, बशर्ते आपने इन वर्गों को स्वयं घोषित किया हो। बेस क्लास में से किसी एक में वर्चुअल विधि जोड़ें और जहां व्युत्पन्न कक्षा में आवश्यक हो, इसे ओवरराइड करें। –

+0

धाराप्रवाह एपीआई के कारण मुझे विस्तार विधियों का उपयोग करना होगा। जेनेरिक विरासत केवल 2 स्तर की विरासत के साथ काम करता है। मैंने गैर-जेनरिक विस्तार विधि के साथ एक उदाहरण लिखा जहां संकलक कॉल करने के लिए सही विधि निर्धारित करने के लिए पैरामीटर प्रतिबंध का उपयोग करता है। मैं बस चाहता हूं कि संकलक सामान्य पैरामीटर प्रतिबंधों का भी मूल्यांकन करे। मैं सार्वजनिक सार्वजनिक टी आईडी (यह टी आइटम, स्ट्रिंग आईडी) के बजाय "सार्वजनिक स्थैतिक बटनबेस आईडी (यह बटनबेस आइटम, स्ट्रिंग आईडी)" नहीं लिख सकता, जहां टी: बटनबेस "क्योंकि वापसी का प्रकार बटनबेस होगा और यह टूट जाएगा धाराप्रवाह एपीआई की विधि श्रृंखला। –

उत्तर

2

आप विस्तार तरीकों के बारे में MSDN प्रलेखन पर एक नज़र ले जा सकते हैं: Extension Methods (C# Programming Guide)। दिलचस्प हिस्सा संकलन समय पर बाध्यकारी एक्सटेंशन पद्धतियों के अंतर्गत है:

... यह पहले प्रकार के उदाहरण के तरीकों में एक मैच के लिए लग रहा है। यदि कोई मिलान नहीं मिलता है, तो यह प्रकार के लिए परिभाषित किए गए किसी भी एक्सटेंशन विधियों की खोज करेगा, और पर पहली एक्सटेंशन विधि से जुड़ें जो इसे पाता है।

तो यही कारण है कि आप इस व्यवहार को देखते हैं। और मैं वास्तव में इसे खरीद सकता हूं, बस कल्पना करें कि कोई व्यक्ति ओवरराइट कर सकता है कि आपका एप्लिकेशन केवल एक विधि public static T Id<T>(this T item, string id) where T : object के साथ कैसे काम करता है। और यदि आपको कोई कंपाइलर त्रुटियां नहीं दिखाई देगी, तो आपको लगता है कि सबकुछ सही है, और शायद कुछ ही काम करेगा, कुछ दुर्लभ मामलों को छोड़कर। यह कितना भ्रमित हो सकता है?

और आपके दृष्टिकोण के बारे में एक और बुरी बात। अगर मैं आपके एपीआई का उपभोग करूंगा और देखता हूं कि बटन के लिए मेरे पास दो विधियां हैं: HtmlElementExtensions में से एक और ButtonBaseExtensions में से एक ButtonExtensions.Id(button, "id") के बजाय HtmlElementExtensions.Id(button, "id") करने से मुझे क्या रोक देगा?

आपके मामले में मैं संयुक्त प्रक्रिया अपनाते हैं:

public static T Id<T>(this T item, string id) where T : HtmlElement 
{ 
    if (item is ButtonBase) 
    { 
     return (T)Id((ButtonBase)item); 
    } 
    else if (item is HtmlElement) 
    { 
     return (T)Id((HtmlElement)item); 
    } 

    throw new NotSupportedException("Type " + item.GetType() + " is not supported by Id extension method"); 
} 

private static ButtonBase Id(ButtonBase item, string id) 
{ 
    return item; 
} 

private static HtmlElement Id(HtmlElement item, string id) 
{ 
    return item; 
} 
+0

मेरे उदाहरण के साथ उपयोगकर्ता मेरी विधियों को ओवरराइट नहीं कर सकता है, क्योंकि विरासत के पेड़ में बटनबेस ऑब्जेक्ट की तुलना में लिंकबटन के बहुत करीब है। और आप वास्तव में दुर्भावनापूर्ण उपयोगकर्ता मानते हैं। मुझे लगता है कि फेंक नया अपवाद() जोड़ने के लिए यह बहुत आसान है; त्रुटियों को बनाने के लिए कोड में। : डी आपका उत्तर मेरे समाधान के समान दिखता है, बस थोड़ा सा सुरुचिपूर्ण :) –

+0

@ पीटर हाँ, क्षमा करें। मैं अलग-अलग दिशा के बारे में सोच रहा था। यदि आपके पास 'बटनबेज' होगा और कोई व्यक्ति 'लिंकबटन' के लिए एक्सटेंशन विधि लिखेंगे। और हां 'संयुक्त दृष्टिकोण' से मेरा मतलब है कि आपके समाधान दोनों एक बार में;) – outcoldman

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