एक्सटेंशन विधि के साथ वर्ग विधि को ओवरराइड करने के लिए C # में कोई तरीका है?


98

ऐसे अवसर आए हैं जहां मैं एक विधि में एक विस्तार विधि के साथ ओवरराइड करना चाहूंगा। क्या ऐसा करने का कोई तरीका C # में है?

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

public static class StringExtension
{
    public static int GetHashCode(this string inStr)
    {
        return MyHash(inStr);
    }
}

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

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

मुझे पता है कि मैं एक मौजूदा वर्ग को हटाकर ऐसा कर सकता हूं लेकिन यह बहुत सारे मामलों में विस्तार के साथ करने में सक्षम होगा।


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

जवाबों:


91

नहीं; एक विस्तार विधि एक उपयुक्त हस्ताक्षर के साथ एक आवृत्ति विधि पर प्राथमिकता नहीं लेती है, और कभी बहुरूपता में भाग नहीं लेती है ( GetHashCodeएक virtualविधि है)।


"" कभी भी बहुरूपता में भाग नहीं लेता है (GetHashCode एक आभासी विधि है) "क्या आप किसी अन्य तरीके से समझा सकते हैं कि एक विस्तार विधि कभी भी आभासी होने के कारण बहुरूपता में भाग नहीं लेगी? मुझे उन दो कथनों के साथ संबंध देखने में समस्या हो रही है।
एलेक्स

3
@ वर्चुअल का उल्लेख करके मैं केवल स्पष्ट कर रहा हूं कि बहुरूपी होने का क्या मतलब है। GetHashCode के लगभग सभी उपयोगों में, ठोस प्रकार अज्ञात है - इसलिए बहुरूपता खेल में है। इस प्रकार, यदि वे नियमित संकलक में प्राथमिकता लेते हैं तो भी विस्तार विधियाँ मदद नहीं करेंगी । ओपी वास्तव में क्या चाहता है बंदर-पैचिंग। जो c # और .net सुविधा नहीं देते हैं।
मार्क Gravell

4
यह दुख की बात है, सी # में इतने सारे भ्रामक गैर-समझदार तरीके हैं, जैसे .ToString()कि सरणियों में। यह निश्चित रूप से एक आवश्यक विशेषता है।
Hi-Angel

फिर आपको संकलक त्रुटि क्यों नहीं मिलती है? जैसे मैं टाइप करता हूं। namespace System { public static class guilty { public static string ToLower(this string s) { return s.ToUpper() + " I'm Malicious"; } } }
लोवलवेल

@LowLevel आप क्यों करेंगे?
मार्क Gravell

7

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

लेकिन अन्यथा आपको वह विरासत का उपयोग करने की आवश्यकता है जो आप देख रहे हैं।


2

जहां तक ​​मुझे पता है कि उत्तर नहीं है, क्योंकि एक विस्तार विधि एक उदाहरण नहीं है। यह मेरे लिए एक अंतःविषय सुविधा की तरह है जो आपको एक वर्ग की आवृत्ति का उपयोग करके एक स्थिर पद्धति को कॉल करने की अनुमति देता है। मुझे लगता है कि आपकी समस्या का समाधान एक इंटरसेप्टर हो सकता है जो एक विशिष्ट विधि के निष्पादन को स्वीकार करता है (जैसे गेटहैशकोड ()) और कुछ और करें। इस तरह के इंटरसेप्टर का उपयोग करें (जैसे कि एक कैसल प्रोजेक्ट प्रदान करता है) सभी वस्तुओं को एक का उपयोग करके इंस्टेंसेट किया जाना चाहिए ऑब्जेक्ट फैक्ट्री (या कैसल में एक आईओसी कंटेनर) ताकि रनटाइम में उत्पन्न एक गतिशील प्रॉक्सी के माध्यम से इंटरसेप्ट किया जा सके। (Caslte भी आपको कक्षाओं के आभासी सदस्यों को इंटरसेप्ट करने देता है)


0

मुझे एक क्लास पद्धति के रूप में एक ही हस्ताक्षर के साथ एक विस्तार विधि को लागू करने का एक तरीका मिल गया है, हालांकि यह बहुत सुरुचिपूर्ण नहीं लगता है। विस्तार के तरीकों के साथ खेलने के दौरान मैंने कुछ अनिर्दिष्ट व्यवहार पर ध्यान दिया। नमूना कोड:

public static class TestableExtensions
{
    public static string GetDesc(this ITestable ele)
    {
        return "Extension GetDesc";
    }

    public static void ValDesc(this ITestable ele, string choice)
    {
        if (choice == "ext def")
        {
            Console.WriteLine($"Base.Ext.Ext.GetDesc: {ele.GetDesc()}");
        }
        else if (choice == "ext base" && ele is BaseTest b)
        {
            Console.WriteLine($"Base.Ext.Base.GetDesc: {b.BaseFunc()}");
        }
    }

    public static string ExtFunc(this ITestable ele)
    {
        return ele.GetDesc();
    }

    public static void ExtAction(this ITestable ele, string choice)
    {
        ele.ValDesc(choice);
    }
}

public interface ITestable
{

}

public class BaseTest : ITestable
{
    public string GetDesc()
    {
        return "Base GetDesc";
    }

    public void ValDesc(string choice)
    {
        if (choice == "")
        {
            Console.WriteLine($"Base.GetDesc: {GetDesc()}");
        }
        else if (choice == "ext")
        {
            Console.WriteLine($"Base.Ext.GetDesc: {this.ExtFunc()}");
        }
        else
        {
            this.ExtAction(choice);
        }
    }

    public string BaseFunc()
    {
        return GetDesc();
    }
}

मैंने जो देखा वह यह था कि अगर मैंने एक एक्सटेंशन विधि के अंदर से दूसरी विधि को कॉल किया, तो यह विस्तार विधि को कॉल करेगा जो हस्ताक्षर से मेल खाता था, भले ही एक वर्ग विधि थी जो हस्ताक्षर से मेल खाती थी। उदाहरण के लिए ऊपर दिए गए कोड में, जब मैं ExtFunc () को कॉल करता हूं, जो बदले में ele.GetDesc () कहता है, तो मुझे स्ट्रिंग "बेस गेटडेस्क" के बजाय रिटर्न स्ट्रिंग "एक्सटेंशन गेटडेस्क" मिलता है जिसकी हम उम्मीद करेंगे।

कोड का परीक्षण:

var bt = new BaseTest();
bt.ValDesc("");
//Output is Base.GetDesc: Base GetDesc
bt.ValDesc("ext");
//Output is Base.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext def");
//Output is Base.Ext.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext base");
//Output is Base.Ext.Base.GetDesc: Base GetDesc

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

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

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