विस्तार के तरीकों के क्या फायदे हैं? [बन्द है]


84

C # का "नॉन-विश्वासी" मुझसे पूछ रहा था कि विस्तार के तरीकों का उद्देश्य क्या है। मैंने समझाया कि आप तब पहले से परिभाषित की गई वस्तुओं में नए तरीके जोड़ सकते हैं, खासकर जब आप मूल वस्तु के स्रोत को नियंत्रित / नियंत्रित नहीं करते हैं।

उन्होंने कहा, "सिर्फ अपने ही वर्ग के लिए एक तरीका क्यों नहीं जोड़ा?" हम (अच्छे तरीके से) गोल-गोल घूम रहे हैं। मेरी सामान्य प्रतिक्रिया यह है कि यह टूलबेल में एक और उपकरण है, और उसकी प्रतिक्रिया है कि यह एक बेकार बेकार उपकरण है ... लेकिन मुझे लगा कि मुझे अधिक "प्रबुद्ध" उत्तर मिलेगा।

कुछ परिदृश्य क्या हैं, जिनका आपने विस्तार विधियों का उपयोग किया है जो आपके पास नहीं हो सकता है (या नहीं होना चाहिए) ने अपनी कक्षा में एक विधि का उपयोग किया है?


2
मुझे लगता है कि निश्चित रूप से वैध तरीके हैं जो लोग विस्तार विधियों के समर्थन में बना सकते हैं (और बना चुके हैं) ... लेकिन निश्चित रूप से ऐसा कोई परिदृश्य नहीं है जहां एक्सटेंशन विधियों के स्थान पर "स्टैटिक विधियों" का उपयोग नहीं किया जा सकता है । एक्सटेंशन विधियां वास्तव में सिर्फ स्थैतिक विधियां हैं, एक अलग तरीके से एक्सेस की जाती हैं। सिर्फ मन में रखने वाली कुछ बातें।
दान ताओ

@DanTao, एक हल्के नोट पर, विस्तार विधि द्वारा कॉल करने वाली एक चीज अपूरणीय है जो उनके बहुत नामकरण हैं। Extensions.To(1, 10)अर्थहीन है और 1.To(10)वर्णनात्मक है। निश्चित रूप से मैं समझ रहा हूं कि आप जिस तकनीकी पक्ष की बात कर रहे हैं, वह सिर्फ कह रहा है। वास्तव में ऐसे परिदृश्य हैं जहां स्थिर तरीकों के स्थान पर एक्सटेंशन दृष्टिकोण का उपयोग "एक" नहीं कर सकता है , उदाहरण के लिए, एक और मामला है dynamic
नवाफाल

जवाबों:


35

मुझे लगता है कि विस्तार के तरीके कोड लिखते समय बहुत मदद करते हैं, यदि आप विस्तार के तरीकों को बुनियादी प्रकारों में जोड़ते हैं तो आप उन्हें इंटेलीजेंस में जल्दी प्राप्त करेंगे।

मैं एक फ़ाइल आकार प्रारूप करने के लिए एक प्रारूप प्रदाता है । इसका उपयोग करने के लिए मुझे लिखना होगा:

Console.WriteLine(String.Format(new FileSizeFormatProvider(), "{0:fs}", fileSize));

एक विस्तार विधि बनाना जो मैं लिख सकता हूं:

Console.WriteLine(fileSize.ToFileSize());

क्लीनर और सरल।


4
आपके एक्सटेंशन विधि के लिए अधिक वर्णनात्मक नाम इसे अभी भी क्लीनर बना देगा। उदा। fileSize.ToFormattedString ();
डेविड अल्परट

1
mmm, ToFormattedFizeSize () हो सकता है, यह लंबे प्रकार के लिए एक विस्तार विधि है, ToFormattedString () एक वर्णनात्मक नाम नहीं है
एडुआर्डो कैम्पानोस

3
बिंदु बनाया, हालांकि। जब मैं फ़ाइल पढ़ता हूं। तो फ़िलेस्लाइज़ () मैं पूछता हूं कि दोहराव क्यों? यह वास्तव में क्या कर रहा है? मुझे पता है कि यह केवल एक उदाहरण है, लेकिन वर्णनात्मक नाम इसे साफ और सरल बनाने में मदद करते हैं।
डेविड अल्परट

1
आप सही हैं परीक्षणों के साथ सही नाम चुनना बहुत महत्वपूर्ण है
एडुआर्डो कैम्पानोस

5
यह वास्तव में सीधे सवाल का जवाब नहीं दे रहा है, हालांकि, आपके द्वारा प्रदान किए गए उदाहरण के बाद से विस्तार विधि की आवश्यकता नहीं है। आप कर सकते थे LongToFileSize(fileSize), जो संक्षिप्त के रूप में और स्पष्ट रूप से स्पष्ट रूप से स्पष्ट है।
दान ताओ

83

केवल विस्तार के तरीकों का लाभ कोड पठनीयता है। बस।

विस्तार विधियाँ आपको यह करने की अनुमति देती हैं:

foo.bar();

इसके अलावा:

Util.bar(foo);

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

विस्तार विधियाँ C # की आंशिक कक्षाओं की तरह होती हैं। अपने आप से वे बहुत सहायक नहीं हैं और तुच्छ लगते हैं। लेकिन जब आप एक ऐसे वर्ग के साथ काम करना शुरू करते हैं जिसे उत्पन्न कोड की आवश्यकता होती है, तो आंशिक कक्षाएं बहुत अधिक समझ में आने लगती हैं।


1
यदि आप x.Foo (कुछ) .Bar (someelse) .Baz (अभी तक) की तरह जंजीर विधियों का उपयोग कर रहे हैं तो यह और भी महत्वपूर्ण हो जाता है। यह IEnumerable <> विस्तार के तरीकों में सबसे अधिक प्रचलित है और पठनीयता में काफी वृद्धि करता है
ShuggyCoUk

2
मुझे जो चीज नहीं मिलती है वह यह है कि foo.bar () मुझे सुझाव देता है कि बार () फू का एक तरीका है। इसलिए जब यह काम नहीं करता है तो मैं गलत जगह देख रहा हूं। मुझे यकीन नहीं है कि यह वास्तव में मेरे लिए एक पठनीयता सुधार है।
मार्टिन ब्राउन

3
वीएस आईडीई में राइट क्लिक बार () और गोटो की परिभाषा के अनुसार आपको सही जगह पर लाना होगा।
जेफ मार्टिन

9
98% भाषा निर्माण का एकमात्र लाभ कोड पठनीयता है। एक शाखा ऑपरेटर, लेबल, गोटो और वेतन वृद्धि के बीच कुछ भी आपके जीवन को थोड़ा आसान बनाने के लिए है।
गियोवन्नी गैल्बो २ 28'०

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

34

टूलींग मत भूलना! जब आप Foo के प्रकार पर एक एक्सटेंशन विधि M जोड़ते हैं, तो आपको फू की इंटेलीसेंस सूची में 'M' मिलता है (एक्सटेंशन वर्ग को मान लेना-गुंजाइश है)। यह 'M' को MyClass.M (Foo, ...) की तुलना में अधिक आसान बनाता है।

दिन के अंत में, यह कहीं और-स्थिर-विधियों के लिए केवल सिन्क्रेटिक चीनी है, लेकिन एक घर खरीदने की तरह है: 'स्थान, स्थान, स्थान!' यदि यह टाइप पर लटका रहता है, तो लोग इसे ढूंढ लेंगे!


2
इसके लिए थोड़ा सा नकारात्मक भी है: विस्तार के तरीके (जैसे कि System.Linq से जो लोग हैं। IntelliSense एक लंबी सूची के साथ स्वत: पूर्ण होता है, जिससे इसे नेविगेट करना थोड़ा कठिन हो जाता है।
Jared Updike

: दूसरा, यह मत भूलो कि बीसीएल (जैसे String) में कक्षाएं हैं जो उदाहरण के तरीकों की एक लंबी सूची के साथ आती हैं, इसलिए यह समस्या विस्तार विधियों के लिए विशिष्ट नहीं है।
स्टाक्स -

29

विस्तार विधियों के दो और लाभ जो मुझे आए हैं:

  • एक धाराप्रवाह इंटरफ़ेस को विस्तार विधियों के एक स्थिर वर्ग में समझाया जा सकता है, जिससे कोर वर्ग के बीच चिंताओं को अलग किया जा सकता है और यह धाराप्रवाह एक्सटेंशन है; मैंने देखा है कि अधिक स्थिरता बनाए रखें।
  • एक्सटेंशन विधियों को इंटरफेस से लटका दिया जा सकता है, जिससे आप एक अनुबंध (एक इंटरफ़ेस के माध्यम से) और इंटरफ़ेस-आधारित व्यवहारों की एक संबंधित श्रृंखला (एक्सटेंशन विधियों के माध्यम से) को निर्दिष्ट कर सकते हैं, फिर से चिंताओं को अलग करने की पेशकश कर सकते हैं। एक उदाहरण Linq विस्तार के तरीकों की तरह कर रहे हैं Select(...), Where(...)आदि त्रिशंकु बंद IEnumerable<T>इंटरफ़ेस।

1
क्या आप बेहतर समझने में मदद करने के लिए दोनों बिंदुओं के लिए कुछ कोड उदाहरणों को उद्धृत कर सकते हैं? यह एक दिलचस्प दृश्य बिंदु प्रतीत होता है।
RBT

हाँ 2 अंक के लिए एक उदाहरण अच्छा होगा।
आईएनसी

26

विस्तार विधियों के लिए मेरे पास सबसे अच्छे उपयोग हैं:

  1. तीसरे पक्ष की वस्तुओं पर कार्यक्षमता बढ़ाएँ (चाहे मेरी कंपनी के लिए वाणिज्यिक या आंतरिक लेकिन एक अलग समूह द्वारा प्रबंधित), जिसे कई मामलों में चिह्नित किया जाएगा sealed
  2. एक अमूर्त वर्ग को लागू किए बिना इंटरफेस के लिए डिफ़ॉल्ट कार्यक्षमता बनाएं

उदाहरण के लिए ले लो IEnumerable<T>। हालांकि यह विस्तार विधियों में समृद्ध है, मुझे यह कष्टप्रद लगा कि इसने जेनेरिक फॉरएच पद्धति को लागू नहीं किया। इसलिए मैंने अपना खुद का बना लिया:

public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
    foreach ( var o in enumerable )
    {
        action(o);
    }
}

वोइला, मेरी सभी IEnumerable<T>वस्तुओं पर, चाहे वे किसी भी प्रकार के हों, और चाहे मैंने इसे लिखा हो या नहीं या किसी और ने अब ForEachमेरे कोड में एक उपयुक्त "स्टेटमेंट" का उपयोग करके एक तरीका जोड़ा है।


3
+1 मुझे यह विस्तार पसंद है, मैंने इसे एक तरह से लिखा। तो बहुत उपयोगी
मास्लो

10
ध्यान दें कि विधि को स्थिर होने की आवश्यकता है। मेरा सुझाव है कि इस एक्सटेंशन का उपयोग करने का निर्णय करने से पहले ब्लॉगs.msdn.com/ericlippert/archive/2009/05/18/… पढ़ें ।
ट्रूविल

IEnumerable पर ForEach एक्सटेंशन पद्धति को लागू करने का कारण सराहना नहीं है - blogs.msdn.microsoft.com/ericlippert/2009/05/18/…
RBT

12

एक्सटेंशन विधियों का उपयोग करने का एक बड़ा कारण LINQ है। विस्तार विधियों के बिना आप लिनक्यू में बहुत कुछ कर सकते हैं जो बहुत कठिन होगा। जहाँ (), सम्‍मिलित है (), एक्‍सटेंशन एक्‍सटेंशन विधियों का अर्थ है कि मौजूदा प्रकार में उनकी संरचना को बदले बिना बहुत अधिक कार्यक्षमता जोड़ी जाती है।


4
इसके 'एक' नहीं, इसके विस्तार के तरीकों का कारण।
gbjbaanb

3
ऐसा कैसे? यह विस्तार विधियों के होने के कई कारणों में से एक है, एकमात्र आवश्यकता नहीं है। मैं LINQ का उपयोग किए बिना एक्सटेंशन विधियों का उपयोग कर सकता हूं।
रे बोयसेन

मुझे लगता है कि इसका मतलब है कि यह कारण था कि वे बनाए गए थे, लेकिन हाँ, वह इसे आवाज़ देता है जैसे कि वे उनके लिए एकमात्र उचित उपयोग हैं।
ब्रेंट रिटेनहाउस

9

एक्सटेंशन विधियों के लाभों के बारे में बहुत सारे उत्तर हैं ; नुकसान के बारे में किसी को कैसे पता चलेगा ?

सबसे बड़ा नुकसान यह है कि यदि आपके पास एक नियमित विधि और एक ही संदर्भ में एक ही हस्ताक्षर के साथ एक विस्तार विधि है, तो कोई संकलक त्रुटि या चेतावनी नहीं है।

मान लीजिए कि आप एक विशेष वर्ग के लिए आवेदन करने की एक विस्तार विधि बनाते हैं। फिर बाद में कोई उस वर्ग पर एक समान हस्ताक्षर के साथ एक विधि बनाता है।

आपका कोड संकलित हो जाएगा, और आपको रनटाइम त्रुटि भी नहीं मिल सकती है। लेकिन अब आप पहले जैसा कोड नहीं चला रहे हैं।


1
4. अपने आप को विस्तारित न करने से पहले दो बार सोचें । यदि आप केवल उन प्रकारों के लिए एक्सटेंशन विधियाँ लिखते हैं जो आप स्वयं करते हैं, तो आपको अपने एक्सटेंशनों के प्रकारों के विस्तार से टूटने के बारे में चिंता करने की आवश्यकता नहीं है। दूसरी ओर, यदि आप अनिवार्य रूप से उनकी दया पर अन्य लोगों के प्रकार का विस्तार कर रहे हैं।
डेविड आरआर

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

एक्सटेंशन मेथड्स (C # प्रोग्रामिंग गाइड) : सामान्य तौर पर, आप शायद अपने खुद के कार्यान्वयन की तुलना में अधिक बार विस्तार विधियों को कॉल करेंगे।
डेविड आरआर

8

कोडबेटर पर ग्रेग यंग द्वारा प्रदर्शित के रूप में धाराप्रवाह इंटरफेस और संदर्भ संवेदनशीलता


4

एक्सटेंशन विधियों के लिए मेरा व्यक्तिगत तर्क है, वे एक ओओपी डिजाइन में बहुत अच्छी तरह से फिट होते हैं: सरल विधि पर विचार करें

bool empty = String.IsNullOrEmpty (myString)

की तुलना में

bool empty = myString.IsNullOrEmpty ();

मैं नहीं देखता कि OOP के साथ आपका क्या उदाहरण है। आपका क्या अर्थ है?
एंड्रयू हरे

1
यह "लगता है" कि विधि वस्तु से संबंधित है
ब्लूएन्सेंस

3
यह एक बुरा उदाहरण है (NullReferenceException को फेंक सकता है) लेकिन वह सही रास्ते पर है। एक बेहतर उदाहरण Math.abs की जगह ले सकता है (-4) जैसे -4.abs ();
डाकू प्रोग्रामर

15
मेरे ज्ञान के लिए (और मेरे अनुभव के लिए, यदि स्मृति कार्य करती है), myString.IsNullOrEmpty () को NullReferenceException को फेंकने की आवश्यकता नहीं है क्योंकि आग लगाने के लिए विस्तार विधियों को ऑब्जेक्ट इंस्टेंस की आवश्यकता नहीं होती है।
डेविड अल्परट

1
मैं व्यक्तिगत रूप से विस्तार के तरीकों का प्रशंसक नहीं हूं, जिनका उद्देश्य एक अशक्त उदाहरण के साथ काम करना है - यह पाठक को एक चीज की तरह दिखता है, लेकिन फिर कुछ और होता है।
मार्क सिम्पसन

4

विस्तार के तरीकों के बारे में महान जवाब के ढेर हैं कि आप क्या करते हैं।

मेरा संक्षिप्त जवाब है - वे लगभग कारखानों की आवश्यकता को समाप्त करते हैं।

मैं सिर्फ यह बताता हूं कि वे एक नई अवधारणा नहीं हैं और उनमें से एक सबसे बड़ी मान्यता यह है कि वे ऑब्जेक्टिव-सी ( श्रेणियों ) में एक हत्यारा विशेषता हैं । वे फ्रेमवर्क आधारित विकास में इतना लचीलापन जोड़ते हैं कि प्रमुख उपयोगकर्ताओं के रूप में नेक्सटी के पास एनएसए और वॉल स्ट्रीट वित्तीय मॉडल हैं।

REALbasic भी उन्हें विस्तार के तरीकों के रूप में लागू करता है और वे विकास को सरल बनाने के समान उपयोग करते हैं।


4

मैं यहां अन्य उत्तरों का समर्थन करना चाहूंगा, जो विस्तार विधियों के पीछे एक महत्वपूर्ण कारण के रूप में बेहतर कोड पठनीयता का उल्लेख करते हैं। मैं इसे इस के दो पहलुओं के साथ प्रदर्शित करूंगा: विधि-पंक्तिबद्धकरण बनाम नेस्टेड विधि कॉल, और व्यर्थ स्थिर स्थिर नामों के साथ एक LINQ क्वेरी की अव्यवस्था।


आइए इस LINQ क्वेरी को एक उदाहरण के रूप में लेते हैं:

numbers.Where(x => x > 0).Select(x => -x)

दोनों Whereऔर Selectविस्तार के तरीकों, स्थिर कक्षा में परिभाषित कर रहे हैं Enumerable। इस प्रकार, यदि विस्तार विधियाँ मौजूद नहीं थीं, और ये सामान्य स्थैतिक विधियाँ थीं, तो कोड की अंतिम पंक्ति को अनिवार्य रूप से इस तरह देखना होगा:

Enumerable.Select(Enumerable.Where(numbers, x => x > 0), x => -x)

देखिए कि बस कितना नस्टियर मिला।


दूसरा, यदि आप अब अपने स्वयं के क्वेरी ऑपरेटर को पेश करना चाहते हैं, तो स्वाभाविक रूप से आपके पास Enumerableअन्य सभी मानक क्वेरी ऑपरेटरों की तरह, स्थिर वर्ग के अंदर इसे परिभाषित करने का कोई तरीका नहीं होगा , क्योंकि Enumerableफ्रेमवर्क में है और आपका उस वर्ग पर कोई नियंत्रण नहीं है। इसलिए, आपको अपने स्वयं के स्थिर वर्ग को विस्तार विधियों से परिभाषित करना होगा। फिर आपको इस तरह के प्रश्न मिल सकते हैं:

Enumerable.Select(MyEnumerableExtensions.RemoveNegativeNumbers(numbers), x => -x)
//                ^^^^^^^^^^^^^^^^^^^^^^
//                different class name that has zero informational value
//                and, as with 'Enumerable.xxxxxx', only obstructs the
//                query's actual meaning.

3

यह सच है कि आप अपनी (विस्तार) विधि को सीधे अपनी कक्षा में जोड़ सकते हैं। लेकिन सभी कक्षाएं आपके द्वारा नहीं लिखी जाती हैं। कोर लाइब्रेरी या थर्ड पार्टी लाइब्रेरी से कक्षाएं अक्सर बंद हो जाती हैं और बिना विस्तार विधियों के सिंटैटिक चीनी प्राप्त करना असंभव होगा। लेकिन याद रखें, विस्तार विधियाँ जैसे (स्थैतिक) स्टैंडअलोन विधियों जैसे हैं। c ++


3

एक्सटेंशन विधियां आपकी कक्षाओं और कक्षा की निर्भरता को साफ रखने में भी मदद कर सकती हैं। उदाहरण के लिए, आपको Foo वर्ग के लिए एक बार () विधि की आवश्यकता हो सकती है हर जगह Foo का उपयोग किया जाता है। हालाँकि, आप किसी अन्य असेंबली में केवल .ToXml () विधि चाहते हैं और कर सकते हैं। उस स्थिति में, आप उस विधानसभा में आवश्यक System.Xml और / या System.Xml.Linq निर्भरताएँ जोड़ सकते हैं और मूल असेंबली में नहीं।

लाभ: आपकी परिभाषित कक्षा की असेंबली में निर्भरता केवल नंगे आवश्यकताओं के लिए कम हो जाती है और अन्य उपभोग्य असेंबलियों को टॉक्सिल () विधि का उपयोग करने से रोका जाएगा। आगे के संदर्भ के लिए इस पीडीसी प्रस्तुति को देखें ।


3

मैं मानता हूं कि विस्तार विधियाँ कोड की पठनीयता को बढ़ाती हैं, लेकिन यह वास्तव में स्थैतिक सहायक विधियों के अलावा और कुछ नहीं है।

IMO अपनी कक्षाओं में व्यवहार जोड़ने के लिए विस्तार विधियों का उपयोग कर सकता है:

भ्रामक: प्रोग्रामर यह मान सकते हैं कि विधियाँ विस्तारित प्रकार का एक हिस्सा हैं, इस प्रकार यह नहीं समझती हैं कि एक्सटेंशन-नेमस्पेस आयात नहीं होने पर विधियाँ क्यों चली जाती हैं।

एक एंटीपैटर: आप विस्तार विधियों का उपयोग करके अपने ढांचे के प्रकारों में व्यवहार को जोड़ने का निर्णय लेते हैं, फिर उन्हें किसी ऐसे व्यक्ति को भेज देते हैं जो इकाई परीक्षण में होता है। अब वह एक ऐसे ढाँचे के साथ फंस गया है जिसमें वह नकली नहीं है।


यह सच नहीं है कि एक डेवलपर तरीकों का एक गुच्छा के साथ फंस गया है वह नकली नहीं हो सकता है। ये विस्तार विधियां अंततः क्लास / इंटरफ़ेस पर कुछ विधि को बुला रही हैं जो वे विस्तार कर रहे हैं और इस पद्धति को इंटरसेप्ट किया जा सकता है जो कि आभासी है।
पैट्रिक हैगन

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

2

विस्तार विधियाँ वास्तव में मार्टिन फॉवलर की पुस्तक (विधि हस्ताक्षर के नीचे) से "विदेशी विधि का परिचय दें" रिफ्लेक्टर की .NET निगमन है । वे मूल रूप से समान लाभ और नुकसान के साथ आते हैं। इस प्रतिक्षेपक पर अनुभाग में वह कहता है कि वे एक काम के आसपास हैं जब आप उस वर्ग को संशोधित नहीं कर सकते हैं जो वास्तव में विधि का मालिक होना चाहिए।


2
+1, लेकिन ध्यान दें कि आप इंटरफेस के साथ एक्सटेंशन विधियों का भी उपयोग कर सकते हैं।
ट्रूविल

2

मैं मुख्य रूप से एक प्रवेश के रूप में विस्तार के तरीकों को देखता हूं कि शायद उन्हें मुफ्त कार्य नहीं करना चाहिए।

C ++ समुदाय में, अक्सर सदस्यों पर मुफ्त नॉनमेम्बर कार्यों को पसंद करने के लिए अच्छा OOP अभ्यास माना जाता है, क्योंकि ये फ़ंक्शन निजी सदस्यों तक पहुंच प्राप्त करने से इनकैप्सुलेशन को नहीं तोड़ते हैं जिनकी उन्हें आवश्यकता नहीं है। उसी तरीके को प्राप्त करने के लिए विस्तार विधियाँ एक गोल चक्कर का रास्ता लगती हैं। यही है, स्थैतिक कार्यों के लिए एक क्लीनर सिंटैक्स जिसकी निजी सदस्यों तक पहुंच नहीं है।

विस्तार विधियां सिंटैक्टिक शुगर से अधिक कुछ नहीं हैं, लेकिन मुझे उनका उपयोग करने में कोई नुकसान नहीं है।


2
  • कुछ बदसूरत उपयोगिता फ़ंक्शन को कॉल करने के बजाय ऑब्जेक्ट पर ही इंटेलीसेन्स
  • रूपांतरण कार्यों के लिए, "XToY (X x)" को "TOY (इस X x)" में बदल सकते हैं, जिसके परिणामस्वरूप बदसूरत XToY (x) के बजाय सुंदर x.ToY () में परिणाम होता है।
  • उन कक्षाओं का विस्तार करें, जिन पर आपका कोई नियंत्रण नहीं है
  • कक्षाओं की कार्यक्षमता का विस्तार करें जब इसके वर्गों में खुद को जोड़ने के लिए अवांछनीय हो। उदाहरण के लिए, आप व्यापारिक वस्तुओं को सरल और तर्क-मुक्त रख सकते हैं, और विस्तार विधियों में बदसूरत निर्भरता के साथ विशिष्ट व्यावसायिक तर्क जोड़ सकते हैं

2

मैं उन्हें अपने ऑब्जेक्ट मॉडल कक्षाओं का पुन: उपयोग करने के लिए उपयोग करता हूं। मेरे पास कक्षाओं का एक समूह है जो एक डेटाबेस में उन वस्तुओं का प्रतिनिधित्व करता है जो मेरे पास हैं। इन वर्गों का उपयोग क्लाइंट साइड में केवल वस्तुओं को प्रदर्शित करने के लिए किया जाता है, इसलिए मूल उपयोग गुणों तक पहुंच रहा है।

public class Stock {
   public Code { get; private set; }
   public Name { get; private set; }
}

उस उपयोग पैटर्न के कारण मैं इन वर्गों में व्यावसायिक तर्क पद्धति नहीं रखना चाहता, इसलिए मैं विस्तार पद्धति होने के लिए प्रत्येक व्यवसाय तर्क देता हूं।

public static class StockExtender {
    public static List <Quote> GetQuotesByDate(this Stock s, DateTime date)
    {...}
}

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

इस समाधान के बारे में एक दिलचस्प बात यह है कि मेरी ऑब्जेक्ट मॉडल कक्षाएं Mono.Cecil का उपयोग करके गतिशील रूप से उत्पन्न होती हैं , इसलिए यदि मैं चाहता हूं तो भी व्यावसायिक तर्क विधियों को जोड़ना बहुत मुश्किल होगा। मेरे पास एक कंपाइलर है जो XML परिभाषा फ़ाइलों को पढ़ता है और डेटाबेस में मेरे पास मौजूद किसी ऑब्जेक्ट का प्रतिनिधित्व करने वाले इन स्टब्स वर्गों को उत्पन्न करता है। इस मामले में एकमात्र दृष्टिकोण उनका विस्तार करना है।


1
आप इसके लिए आंशिक कक्षाओं का उपयोग कर सकते हैं ...
JJoos


1

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


1

एक मामला जहां एक्सटेंशन के तरीके काफी उपयोगी थे, एक ग्राहक-अनुप्रयोग में था जो ASMX वेब सेवाओं का उपयोग करता है। क्रमांकन के कारण, वापसी के प्रकार के वेब तरीकों में कोई विधि नहीं होती है (केवल ग्राहक पर इन प्रकारों के सार्वजनिक गुण उपलब्ध हैं)।

एक्सटेंशन विधियों ने वेब विधियों द्वारा लौटाए गए प्रकारों के लिए क्लाइंट-साइड पर कार्यक्षमता (क्लाइंट-साइड पर) जोड़ने की अनुमति दी, फिर भी क्लाइंट-साइड पर एक अन्य ऑब्जेक्ट मॉडल या कई आवरण कक्षाएं बनाने के लिए।


1

एक्सटेंशन विधियों का उपयोग एक प्रकार के मिक्सिन बनाने के लिए किया जा सकता है C # में ।

यह, बदले में, ऑर्थोगोनल अवधारणाओं के लिए चिंताओं का बेहतर पृथक्करण प्रदान करता है। इस जवाब पर एक नज़र डालें को एक उदाहरण के रूप में देखें।

इसका उपयोग C # में भूमिकाओं को सक्षम करने के लिए भी किया जा सकता है , जो DCI आर्किटेक्चर के लिए एक अवधारणा केंद्रीय है ।


1

यह भी याद रखें कि लिनेक क्वेरी को अधिक पठनीय बनाने में मदद करने के लिए एक विस्तार तरीके के रूप में जोड़ा गया था, जब उनका सी # शैली में उपयोग किया जाता था।

ये 2 प्रभाव बिल्कुल समतुल्य हैं, फिर भी पहले से बहुत अधिक पठनीय है (और पठनीयता में अंतर अधिक विधियों के साथ बढ़ेगा)।

int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();

int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));

ध्यान दें कि पूरी तरह से योग्य सिंटैक्स भी होना चाहिए:

int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();

int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));

संयोग से, के प्रकार के मापदंडों Where और Lastस्पष्ट रूप से उल्लेख किया जाना के रूप में वे इन दोनों तरीकों के पहले पैरामीटर (पैरामीटर जो कीवर्ड द्वारा शुरू की है की उपस्थिति के लिए धन्यवाद infered किया जा सकता है की जरूरत नहीं हैthis है और उन्हें विस्तार तरीकों बनाने)।

यह बिंदु स्पष्ट रूप से विस्तार के तरीकों का एक फायदा (दूसरों के बीच) है, और आप हर समान परिदृश्य में इसका लाभ उठा सकते हैं जहां विधि का समावेश होता है।

विशेष रूप से, यह अधिक सुंदर और आश्वस्त करने वाला तरीका है जो मुझे किसी भी उपवर्ग द्वारा एक बेस क्लास विधि को अदृश्य करने के लिए मिला है और इस उपवर्ग (उपवर्ग प्रकार के साथ) को दृढ़ता से टाइप किया गया संदर्भ लौटाता है।

उदाहरण (ठीक है, यह परिदृश्य पूरी तरह से लजीज है): एक अच्छी रात के बाद, एक जानवर आँखें खोलता है फिर रोता है; हर जानवर उसी तरह से आँखें खोलता है, जबकि एक कुत्ता भौंकता है और एक बत्तख का बच्चा।

public abstract class Animal
{
    //some code common to all animals
}

public static class AnimalExtension
{
    public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return animal; //returning a self reference to allow method chaining
    }
}

public class Dog : Animal
{
    public void Bark() { /* ... */ }
}

public class Duck : Animal
{
    public void Kwak() { /* ... */ }
}

class Program
{
    static void Main(string[] args)
    {
        Dog Goofy = new Dog();
        Duck Donald = new Duck();
        Goofy.OpenTheEyes().Bark(); //*1
        Donald.OpenTheEyes().Kwak(); //*2
    }
}

सैद्धांतिक रूप OpenTheEyesसे एक होना चाहिए Animalविधि है, लेकिन यह तो अमूर्त वर्ग का एक उदाहरण वापसी होगी Animal, जो जैसे विशिष्ट उपवर्ग तरीकों पता नहीं है Barkया Duckया जो कुछ भी। 2 पंक्तियों के रूप में टिप्पणी * 1 और * 2 तब एक संकलन त्रुटि उठाएगा।

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

ध्यान दें कि एक सामान्य सामान्य विधि काम कर सकती थी, लेकिन कहीं अधिक अजीब तरीके से:

public abstract class Animal
{
    //some code common to all animals

    public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return (TAnimal)this; //returning a self reference to allow method chaining
    }
}

इस बार, कोई पैरामीटर नहीं है और इस प्रकार कोई संभावित वापसी प्रकार का अनुमान नहीं है। कॉल के अलावा कुछ नहीं हो सकता है:

Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();

... जो कोड को बहुत अधिक वजन कर सकता है यदि अधिक चैनिंग शामिल है (विशेष रूप से यह जानते हुए कि प्रकार पैरामीटर हमेशा <Dog>नासमझ की लाइन <Duck>पर और डोनाल्ड एक पर होगा ...)


1
पहली बार मैंने कभी "kwak" देखा है। क्या यह एक वर्तनी है जो दूसरे देश में आम है? एकमात्र तरीका जो मैंने कभी देखा है वह है "क्वैक।"
ब्रेंट रिटेनहाउस

0

मेरे पास इसके बारे में बताने के लिए केवल एक शब्द है: MAINTAINABILITY यह विस्तार विधियों के उपयोग की कुंजी है


4
मुझे लगता है कि आपको एक से अधिक शब्दों की आवश्यकता हो सकती है क्योंकि मुझे समझ में नहीं आता कि इसका क्या मतलब है।
आउटलॉव प्रोग्रामर

2
मैं वास्तव में कहूंगा कि एक्स्टेंशन के तरीकों के खिलाफ एक तर्क है । लुप्त होने के तरीकों में से एक जोखिम यह है कि वे हर जगह हो सकते हैं, सभी के द्वारा बनाई गई हैं। वाइल्डग्रो हो सकता है अगर सावधानी से इस्तेमाल न किया जाए।
बोरिस कॉल

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

0

मुझे लगता है कि विस्तार विधियाँ कोड को लिखने में मदद करती हैं जो स्पष्ट है।

अपनी कक्षा के अंदर एक नई विधि डालने के बजाय, जैसा कि आपके मित्र ने सुझाया था, आपने उसे ExtensionMethods नामस्थान में डाल दिया। इस तरह आप अपनी कक्षा को तार्किक समझ बनाए रखते हैं। ऐसे तरीके जो वास्तव में सीधे आपकी कक्षा से सीधे नहीं निपटते हैं, वे इसे अव्यवस्थित नहीं करेंगे।

मुझे लगता है कि विस्तार के तरीके आपके कोड को स्पष्ट और अधिक उचित रूप से व्यवस्थित करते हैं।


0

यह आपके संपादक / IDE को ऑटो-पूर्ण सुझाव को स्मार्ट बनाने की अनुमति देता है।


0

मैं उन्हें html बनाने के लिए प्यार करता हूँ। अक्सर ऐसे खंड होते हैं जो बार-बार उपयोग किए जाते हैं, या पुनरावर्ती रूप से उत्पन्न होते हैं जहां एक फ़ंक्शन उपयोगी होता है, लेकिन अन्यथा कार्यक्रम के प्रवाह को तोड़ देगा।

        HTML_Out.Append("<ul>");
        foreach (var i in items)
            if (i.Description != "")
            {
                HTML_Out.Append("<li>")
                    .AppendAnchor(new string[]{ urlRoot, i.Description_Norm }, i.Description)
                    .Append("<div>")
                    .AppendImage(iconDir, i.Icon, i.Description)
                    .Append(i.Categories.ToHTML(i.Description_Norm, urlRoot)).Append("</div></li>");
            }

        return HTML_Out.Append("</ul>").ToString();

ऐसी स्थितियां भी हैं जहां HTML आउटपुट के लिए किसी ऑब्जेक्ट को कस्टम लॉजिक तैयार करने की आवश्यकता होती है- विस्तार के तरीके आपको क्लास के भीतर प्रस्तुति और लॉजिक को मिलाए बिना इस कार्यक्षमता को जोड़ते हैं।


0

मैंने पाया है कि विस्तार विधियाँ नेस्टेड जेनेरिक तर्कों से मेल खाने के लिए उपयोगी हैं।

यह थोड़ा अजीब लगता है - लेकिन कहते हैं कि हमारे पास एक सामान्य वर्ग है MyGenericClass<TList> , और हम जानते हैं कि TList खुद ही सामान्य है (उदाहरण के लिए)List<T> ) है, मुझे नहीं लगता है कि सूची से 'नेस्टेड' T को खोदने का कोई तरीका है या तो विस्तार के बिना। विधियाँ या स्थैतिक सहायक विधियाँ। यदि हमारे पास हमारे निपटान में केवल स्थैतिक सहायक विधियां हैं, तो यह (ए) बदसूरत है, और (बी) हमें कार्यक्षमता को स्थानांतरित करने के लिए मजबूर करेगा जो कक्षा में बाहरी स्थान पर है।

टपल में प्रकारों को पुनः प्राप्त करने और उन्हें एक विधि हस्ताक्षर में बदलने के लिए जैसे हम एक्सटेंशन विधियों का उपयोग कर सकते हैं:

public class Tuple { }
public class Tuple<T0> : Tuple { }
public class Tuple<T0, T1> : Tuple<T0> { }

public class Caller<TTuple> where TTuple : Tuple { /* ... */ }

public static class CallerExtensions
{
     public static void Call<T0>(this Caller<Tuple<T0>> caller, T0 p0) { /* ... */ }

     public static void Call<T0, T1>(this Caller<Tuple<T0, T1>> caller, T0 p0, T1 p1) { /* ... */ }
}

new Caller<Tuple<int>>().Call(10);
new Caller<Tuple<string, int>>().Call("Hello", 10);

उस ने कहा, मुझे यकीन नहीं है कि विभाजन रेखा कहाँ होनी चाहिए - जब एक विधि एक विस्तार विधि होनी चाहिए, और यह एक स्थिर सहायक विधि कब होनी चाहिए? कोई विचार?


0

मेरी स्क्रीन पर मेरे पास इनपुट क्षेत्र हैं, और सभी को एक मानक व्यवहार को लागू करना चाहिए जो भी उनके सटीक प्रकार हैं (टेक्स्टबॉक्स, चेकबॉक्स, आदि)। वे एक सामान्य आधार वर्ग को प्राप्त नहीं कर सकते हैं क्योंकि प्रत्येक प्रकार का इनपुट क्षेत्र पहले से ही एक विशिष्ट वर्ग (TextInputBox, आदि) से प्राप्त होता है।

हो सकता है विरासत वंशानुक्रम में ऊपर जाने से मुझे वेबकंट्रोल के समान एक सामान्य पूर्वज मिल जाए, लेकिन मैंने फ्रेमवर्क वर्ग वेबकंट्रोल का विकास नहीं किया और यह वह नहीं प्रकट करता है जिसकी मुझे आवश्यकता है।

विस्तार विधि के साथ, मैं कर सकता हूँ:

1) वेबकंट्रोल क्लास का विस्तार करें, और फिर अपने सभी इनपुट कक्षाओं पर मेरे एकीकृत मानक व्यवहार को प्राप्त करें

2) वैकल्पिक रूप से मेरे सभी वर्गों को एक अंतरफलक से प्राप्त करें, IInputZone कहते हैं, और इस इंटरफ़ेस को विधियों के साथ विस्तारित करें। अब मैं अपने सभी इनपुट ज़ोन पर इंटरफ़ेस से संबंधित एक्सटेंशन विधियों को कॉल कर सकूंगा। इस प्रकार मैंने कई प्रकार की विरासत प्राप्त की क्योंकि मेरे इनपुट क्षेत्र पहले से ही कई आधार वर्गों से प्राप्त हुए हैं।


0

विस्तार के तरीकों के कई महान उदाहरण हैं..आसानी से IEnumerables पर जैसा कि ऊपर पोस्ट किया गया है।

उदाहरण के लिए यदि मेरे पास एक IEnumerable<myObject>I है और इसके लिए विस्तार विधि बना सकता हूंIEnumerable<myObject>

mylist List<myObject>;

... सूची बनाएं

mylist.DisplayInMyWay();

एक्सटेंशन के तरीकों के बिना कॉल करना होगा:

myDisplayMethod(myOldArray); // can create more nexted brackets.

एक और महान उदाहरण एक फ्लैश में एक परिपत्र लिंक्ड सूची बना रहा है!

मैं इसका श्रेय ले सकता हूं!

एक्सटेंशन मेथड्स का उपयोग कर सर्कुलर लिंक्ड सूची

अब इन्हें मिलाएं और विस्तार विधि कोड का उपयोग करके निम्नानुसार पढ़ता है।

myNode.NextOrFirst().DisplayInMyWay();

बजाय

DisplayInMyWay(NextOrFirst(myNode)).

एक्सटेंशन मेथड्स का उपयोग करना, यह अधिक सरल और पढ़ने में आसान है और अधिक ऑब्जेक्ट ओरिएंटेड है। इसके बहुत करीब:

myNode.Next.DoSomething()

अपने कोलीग को दिखाओ! :)

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