C # - कीवर्ड उपयोग वर्चुअल + ओवरराइड बनाम नया


204

आधार प्रकार में एक विधि घोषित करने के बीच क्या अंतर हैं virtual"और फिर बच्चे के प्रकार में" override"कीवर्ड का उपयोग करते हुए ओवरडाइडिंग का उपयोग करते हुए" टाइप करने के लिए विरोध किया जाता है new?


3
MSDN का कहना है कि " newएक ही नाम के साथ एक नए सदस्य का उपयोग करना और मूल सदस्य के छिपे होने का कारण बनता है, जबकि overrideविरासत में दिए गए सदस्य के लिए कार्यान्वयन का विस्तार करता है"
AminM


जवाबों:


181

"नया" कीवर्ड ओवरराइड नहीं करता है, यह एक नई विधि को दर्शाता है जिसका आधार वर्ग विधि से कोई लेना-देना नहीं है।

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 से लिया गया आधार कोड)

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


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

1
धन्यवाद, मैंने "स्थिर" भाग को याद किया। भविष्य पर अधिक ध्यान देना चाहिए
एलबर्टिन

1
ध्यान दें कि यहां लाइन फू टेस्ट = नया बार () महत्वपूर्ण है, मेट्रो के लिए नया / ओवरराइड कीवर्ड यह निर्धारित करता है कि जब आप एक बार को फू चर में डालते हैं तो मेट्रो को क्या कहा जाता है।
थॉमस एन

... तो यह बस के रूप में ठीक उसी है नहीं होने virtualआधार में और overrideव्युत्पन्न में? इसका अस्तित्व क्यों है? कोड अभी भी w / o चलेगा new- तो क्या यह विशुद्ध रूप से सिर्फ पठनीयता है?
डॉन चीडल

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

228

मैं हमेशा इस तरह की चीजों को चित्रों के साथ आसानी से समझ पाता हूं:

फिर, जोसेफ 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जब अपनी कक्षाओं की घोषणा।

वर्चुअल / ओवरराइड स्पष्टीकरण छवि


3
धन्यवाद .... लेकिन क्या आप ऊपर बताई गई तस्वीर के बारे में थोड़ा बता सकते हैं?
odiseh

उफ़ अगर ये कुछ लाइन मेरे प्राइम में जोड़ना भूल गया। टिप्पणी: क्या आपका मतलब है कि वर्चुअल / ओवरराइडिंग और गैर-विएतुल्य / नए का उपयोग सिर्फ बहुरूपता अवधारणा के लिए किया जाता है और जब आप केवल एक चर घोषित करते हैं (कास्टिंग का उपयोग नहीं करते) तो उनका मतलब यह नहीं है? एक बार फिर धन्यवाद।
odiseh

यह उत्तर वही है जिसकी मुझे तलाश थी। मेरे पास एकमात्र समस्या यह है कि फ़्लिकर छवियां मेरे कार्यस्थल पर अवरुद्ध हैं, इसलिए मुझे अपने फोन के माध्यम से इसे एक्सेस करना पड़ा ...
mezoid

7
प्रश्न का उत्तर देने का वास्तविक प्रयास।
iMatoria

यदि आप छवि को ठीक कर सकते हैं तो मैं बढ़ाऊंगा? कॉर्प फायरवॉल के पीछे इसका अवरोध ...
जेरेमी थॉम्पसन

43

आभासी और गैर-आभासी तरीकों के व्यवहार में अंतर को समझने के लिए यहां कुछ कोड दिए गए हैं:

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आधार विधि को "छिपाने" के लिए उपयोग क्यों करें , जब ओवरराइड का उपयोग नहीं करने से ऐसा ही लगता है?
डॉन चीडल

1
मुझे नहीं लगता कि इसे बेस क्लास को ओवरराइड होने से रोकने के लिए बनाया गया था। मुझे लगता है कि यह नाम के टकराव से बचने के लिए बनाया गया था क्योंकि आप एक ऐसी विधि को ओवरराइड नहीं कर सकते जो कि नहीं है virtualऔर कंपाइलर शिकायत करेगा यदि यह एक ही फ़ंक्शन नाम को एक वर्ग " virtual
रक्तरेखा

19

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


9

वर्चुअल / ओवरराइड कंपाइलर को बताता है कि दो विधियां संबंधित हैं और कुछ परिस्थितियों में जब आपको लगता है कि आप पहली (आभासी) पद्धति को कॉल कर रहे हैं तो वास्तव में इसके बजाय दूसरी (ओवरराइड) विधि को कॉल करना सही है। यह बहुरूपता की नींव है।

(new SubClass() as BaseClass).VirtualFoo()

SubClass की ओवरराइड VirtualFoo () विधि को कॉल करेगा।

नवीन कंपाइलर को बताता है कि आप एक विधि को आधार वर्ग में विधि के समान नाम के साथ एक व्युत्पन्न वर्ग में जोड़ रहे हैं, लेकिन उनका एक दूसरे से कोई संबंध नहीं है।

(new SubClass() as BaseClass).NewBar()

BaseClass की NewBar () विधि को कॉल करेगा, जबकि:

(new SubClass()).NewBar()

SubClass की NewBar () विधि को कॉल करेगा।


वास्तव में यह वाक्य "संकलक को बताता है"
मीना गेब्रियल

"बहुरूपता की नींव" एक और उत्तम दर्जे की कहावत है :)
जेरेमी थॉम्पसन

8

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


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

4

ओवरराइड कीवर्ड और नए कीवर्ड के बीच का अंतर यह है कि पूर्व ओवरराइडिंग विधि करता है और बाद में विधि छुपाता है।

अधिक जानकारी के लिए folllowing लिंक देखें ...

MSDN और अन्य


3
  • newकीवर्ड छुपाने के लिए है। - इसका मतलब है कि आप अपनी विधि को रनटाइम पर छिपा रहे हैं। आउटपुट बेस क्लास विधि होगी।
  • overrideओवरराइडिंग के लिए। - इसका मतलब है कि आप बेस क्लास के संदर्भ के साथ अपनी व्युत्पन्न वर्ग पद्धति को लागू कर रहे हैं। आउटपुट व्युत्पन्न वर्ग विधि पर आधारित होगा।

1

मतभेदों को समझने में मदद करने के लिए गुणों का उपयोग करने से स्पष्टीकरण का मेरा संस्करण आता है ।

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


0

किसी भी चीज़ के साथ एक विधि को चिह्नित नहीं करना है: ऑब्जेक्ट के संकलित प्रकार का उपयोग करके इस विधि को बांधें, न कि रनटाइम प्रकार (स्थिर बंधन)।

विधि के साथ एक विधि को चिह्नित करना virtual: इस विधि को ऑब्जेक्ट के रनटाइम प्रकार का उपयोग करके बांधें, न कि समय प्रकार (डायनामिक बाइंडिंग) को संकलित करें।

व्युत्पन्न वर्ग के virtualसाथ एक बेस क्लास विधि को चिह्नित करने का overrideअर्थ है: यह ऑब्जेक्ट के रनटाइम प्रकार (डायनामिक बाइंडिंग) का उपयोग करके बाध्य होने की विधि है।

व्युत्पन्न वर्ग के virtualसाथ एक बेस क्लास पद्धति को चिह्नित करने का newअर्थ है: यह एक नई विधि है, जिसका आधार वर्ग में समान नाम के साथ किसी से कोई संबंध नहीं है और इसे ऑब्जेक्ट के संकलन समय प्रकार (स्थिर बंधन) का उपयोग करके बाध्य किया जाना चाहिए।

virtualव्युत्पन्न वर्ग में आधार वर्ग विधि का अंकन नहीं होता है: इस विधि को new(स्थैतिक बंधन) के रूप में चिह्नित किया जाता है ।

एक विधि को चिह्नित करने का abstractअर्थ है: यह विधि आभासी है, लेकिन मैं इसके लिए एक निकाय घोषित नहीं करूंगा और इसकी कक्षा भी सार (डायनामिक बाइंडिंग) है।

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