आधार प्रकार में एक विधि घोषित करने के बीच क्या अंतर हैं virtual
"और फिर बच्चे के प्रकार में" override
"कीवर्ड का उपयोग करते हुए ओवरडाइडिंग का उपयोग करते हुए" टाइप करने के लिए विरोध किया जाता है new
?
आधार प्रकार में एक विधि घोषित करने के बीच क्या अंतर हैं virtual
"और फिर बच्चे के प्रकार में" override
"कीवर्ड का उपयोग करते हुए ओवरडाइडिंग का उपयोग करते हुए" टाइप करने के लिए विरोध किया जाता है new
?
जवाबों:
"नया" कीवर्ड ओवरराइड नहीं करता है, यह एक नई विधि को दर्शाता है जिसका आधार वर्ग विधि से कोई लेना-देना नहीं है।
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
public class Test
{
public static void Main ()
{
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
यह गलत प्रिंट करता है, यदि आप ओवरराइड करते थे तो यह सच प्रिंट होता था।
(जोसेफ Daigle से लिया गया आधार कोड)
तो, अगर आप असली बहुरूपता कर रहे हैं, तो आप हमेशा ही दूर रहें । एकमात्र स्थान जहां आपको "नया" उपयोग करने की आवश्यकता होती है, जब विधि किसी भी तरह से आधार वर्ग संस्करण से संबंधित नहीं होती है।
virtual
आधार में और override
व्युत्पन्न में? इसका अस्तित्व क्यों है? कोड अभी भी w / o चलेगा new
- तो क्या यह विशुद्ध रूप से सिर्फ पठनीयता है?
मैं हमेशा इस तरह की चीजों को चित्रों के साथ आसानी से समझ पाता हूं:
फिर, जोसेफ daigle कोड लेने,
public class Foo
{
public /*virtual*/ bool DoSomething() { return false; }
}
public class Bar : Foo
{
public /*override or new*/ bool DoSomething() { return true; }
}
यदि आप कोड को इस तरह कहते हैं:
Foo a = new Bar();
a.DoSomething();
नोट: महत्वपूर्ण बात यह है कि हमारी वस्तु वास्तव में एक है Bar
, लेकिन हम इसे एक प्रकार के चर में संग्रहीतFoo
कर रहे हैं (यह कास्टिंग के समान है)
फिर परिणाम, के रूप में इस प्रकार है पर कि क्या आप इस्तेमाल किया आधार पर किया जाएगा virtual
/ override
या new
जब अपनी कक्षाओं की घोषणा।
आभासी और गैर-आभासी तरीकों के व्यवहार में अंतर को समझने के लिए यहां कुछ कोड दिए गए हैं:
class A
{
public void foo()
{
Console.WriteLine("A::foo()");
}
public virtual void bar()
{
Console.WriteLine("A::bar()");
}
}
class B : A
{
public new void foo()
{
Console.WriteLine("B::foo()");
}
public override void bar()
{
Console.WriteLine("B::bar()");
}
}
class Program
{
static int Main(string[] args)
{
B b = new B();
A a = b;
a.foo(); // Prints A::foo
b.foo(); // Prints B::foo
a.bar(); // Prints B::bar
b.bar(); // Prints B::bar
return 0;
}
}
new
आधार विधि को "छिपाने" के लिए उपयोग क्यों करें , जब ओवरराइड का उपयोग नहीं करने से ऐसा ही लगता है?
virtual
और कंपाइलर शिकायत करेगा यदि यह एक ही फ़ंक्शन नाम को एक वर्ग " virtual
new
कीवर्ड का वास्तव में एक पूरी तरह से नए सदस्य है कि केवल उस विशिष्ट प्रकार पर मौजूद रहता है।
उदाहरण के लिए
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
विधि दोनों प्रकारों पर मौजूद है। जब आप परावर्तन का उपयोग करते हैं और प्रकार के सदस्य प्राप्त करते हैं Bar
, तो आप वास्तव में 2 विधियों को खोजेंगे, जिन्हें DoSomething()
वास्तव में एक जैसा कहा जाता है। उपयोग करके new
आप प्रभावी रूप से बेस क्लास में कार्यान्वयन को छिपाते हैं, ताकि जब कक्षाएं Bar
(मेरे उदाहरण में) से निकले तो विधि कॉल को base.DoSomething()
जाना Bar
और न जाना Foo
।
वर्चुअल / ओवरराइड कंपाइलर को बताता है कि दो विधियां संबंधित हैं और कुछ परिस्थितियों में जब आपको लगता है कि आप पहली (आभासी) पद्धति को कॉल कर रहे हैं तो वास्तव में इसके बजाय दूसरी (ओवरराइड) विधि को कॉल करना सही है। यह बहुरूपता की नींव है।
(new SubClass() as BaseClass).VirtualFoo()
SubClass की ओवरराइड VirtualFoo () विधि को कॉल करेगा।
नवीन कंपाइलर को बताता है कि आप एक विधि को आधार वर्ग में विधि के समान नाम के साथ एक व्युत्पन्न वर्ग में जोड़ रहे हैं, लेकिन उनका एक दूसरे से कोई संबंध नहीं है।
(new SubClass() as BaseClass).NewBar()
BaseClass की NewBar () विधि को कॉल करेगा, जबकि:
(new SubClass()).NewBar()
SubClass की NewBar () विधि को कॉल करेगा।
सिर्फ तकनीकी विवरणों के अलावा, मुझे लगता है कि वर्चुअल / ओवरराइड का उपयोग करने से डिजाइन पर बहुत अधिक अर्थपूर्ण जानकारी का संचार होता है। जब आप किसी विधि को वर्चुअल घोषित करते हैं, तो आप संकेत देते हैं कि आप उम्मीद करते हैं कि कार्यान्वयन करने वाली कक्षाएं अपना स्वयं का, गैर-डिफ़ॉल्ट कार्यान्वयन प्रदान करना चाहेंगी। इसी तरह एक आधार वर्ग में, इस उम्मीद को घोषित करता है कि सभी लागू वर्गों के लिए डिफ़ॉल्ट विधि को पर्याप्त होना चाहिए। इसी तरह, अमूर्त घोषणाओं का उपयोग कार्यान्वयन वर्गों को अपने स्वयं के कार्यान्वयन को प्रदान करने के लिए मजबूर करने के लिए कर सकते हैं। फिर से, मुझे लगता है कि यह इस बारे में बहुत कुछ बताता है कि प्रोग्रामर कोड का उपयोग कैसे करता है। यदि मैं दोनों आधार और कार्यान्वयन कक्षाएं लिख रहा था और नए का उपयोग करके खुद को पाया, तो मैं गंभीरता से माता-पिता में विधि को आभासी नहीं बनाने के फैसले पर पुनर्विचार करता हूं और विशेष रूप से अपने इरादे की घोषणा करता हूं।
मतभेदों को समझने में मदद करने के लिए गुणों का उपयोग करने से स्पष्टीकरण का मेरा संस्करण आता है ।
override
काफी सरल है, है ना? अंतर्निहित प्रकार माता-पिता को ओवरराइड करता है।
new
शायद भ्रामक है (मेरे लिए यह था)। गुणों के साथ यह समझना आसान है:
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
एक डिबगर का उपयोग करके आप कि नोटिस कर सकते हैं Foo foo
है 2 GetSomething
, गुण के रूप में यह वास्तव में संपत्ति के 2 संस्करण है, Foo
के और Bar
की, और पता करने के लिए जो प्रयोग करने के लिए एक, सी # "पसंद" वर्तमान प्रकार के लिए संपत्ति।
यदि आप बार के संस्करण का उपयोग करना चाहते हैं, तो आपने Foo foo
इसके बजाय ओवरराइड या उपयोग किया होगा ।
Bar bar
केवल 1 है , क्योंकि यह पूरी तरह से नया व्यवहार चाहता है GetSomething
।
किसी भी चीज़ के साथ एक विधि को चिह्नित नहीं करना है: ऑब्जेक्ट के संकलित प्रकार का उपयोग करके इस विधि को बांधें, न कि रनटाइम प्रकार (स्थिर बंधन)।
विधि के साथ एक विधि को चिह्नित करना virtual
: इस विधि को ऑब्जेक्ट के रनटाइम प्रकार का उपयोग करके बांधें, न कि समय प्रकार (डायनामिक बाइंडिंग) को संकलित करें।
व्युत्पन्न वर्ग के virtual
साथ एक बेस क्लास विधि को चिह्नित करने का override
अर्थ है: यह ऑब्जेक्ट के रनटाइम प्रकार (डायनामिक बाइंडिंग) का उपयोग करके बाध्य होने की विधि है।
व्युत्पन्न वर्ग के virtual
साथ एक बेस क्लास पद्धति को चिह्नित करने का new
अर्थ है: यह एक नई विधि है, जिसका आधार वर्ग में समान नाम के साथ किसी से कोई संबंध नहीं है और इसे ऑब्जेक्ट के संकलन समय प्रकार (स्थिर बंधन) का उपयोग करके बाध्य किया जाना चाहिए।
virtual
व्युत्पन्न वर्ग में आधार वर्ग विधि का अंकन नहीं होता है: इस विधि को new
(स्थैतिक बंधन) के रूप में चिह्नित किया जाता है ।
एक विधि को चिह्नित करने का abstract
अर्थ है: यह विधि आभासी है, लेकिन मैं इसके लिए एक निकाय घोषित नहीं करूंगा और इसकी कक्षा भी सार (डायनामिक बाइंडिंग) है।
new
एक ही नाम के साथ एक नए सदस्य का उपयोग करना और मूल सदस्य के छिपे होने का कारण बनता है, जबकिoverride
विरासत में दिए गए सदस्य के लिए कार्यान्वयन का विस्तार करता है"