विधि हस्ताक्षर में नया कीवर्ड


113

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

मैंने पहले इस तरह एक असाइनमेंट स्टेटमेंट दिया था:

MyObject myVar = new MyObject();

इसे दुर्घटना से बदल दिया गया था:

private static new MyObject CreateSomething()
{
  return new MyObject{"Something New"};
}

यह मेरी ओर से कट / पेस्ट त्रुटि का परिणाम था, लेकिन इसमें newकीवर्ड private static newमान्य और संकलित है।

प्रश्न : newविधि हस्ताक्षर में कीवर्ड क्या दर्शाता है? मुझे लगता है कि यह C # 3.0 में पेश किया गया है?

यह कैसे अलग है override?


5
छिपाने की वांछनीयता पर कुछ नोट्स: blogs.msdn.com/ericlippert/archive/2008/05/21/…
एरिक

2
@ ईरिक .. महान पोस्ट। मैंने कभी भी उस तरीके को छिपाने के बारे में नहीं सोचा था, जैसा कि हां, वस्तु एक चीज है, लेकिन हम अब इसे कुछ और के रूप में पेश कर रहे हैं, इसलिए हम उस चीज का व्यवहार चाहते हैं जिसे हम इसे प्रस्तुत कर रहे हैं। चतुर ...
BFree

1
भविष्य में एक डुप्लिकेट प्रश्न और मैंने कुछ विस्तार से उत्तर देने की कोशिश की है: c # में नए कीवर्ड का उपयोग करें
केन किन

1
newएक विधि (या अन्य प्रकार के सदस्य) पर आ मॉडिफ़ायर के रूप में उपयोग "C # 3.0 में प्रस्तुत कुछ" नहीं है। यह C # के पहले संस्करण के बाद से ही है।
जेपी स्टिग नील्सन

1
एसओ में इस सवाल के 4 डुप्लिकेट की तरह है। मेरी राय में, यह आपको सबसे अच्छी समझ देगा: stackoverflow.com/questions/3117838/… । इसका उत्तर @EricLippert द्वारा दिया गया है।
रायकोल अमारो

जवाबों:


101

MSDN से नया कीवर्ड संदर्भ:

MSDN संदर्भ

यहां एक उदाहरण है जो मुझे एक Microsoft MVP से नेट पर मिला, जिसने अच्छी समझ बनाई: लिंक टू ओरिजिनल

public class A
{
   public virtual void One();
   public void Two();
}

public class B : A
{
   public override void One();
   public new void Two();
}

B b = new B();
A a = b as A;

a.One(); // Calls implementation in B
a.Two(); // Calls implementation in A
b.One(); // Calls implementation in B
b.Two(); // Calls implementation in B

ओवरराइड का उपयोग केवल बहुत विशिष्ट मामलों में किया जा सकता है। MSDN से:

आप एक गैर-आभासी या स्थिर विधि को ओवरराइड नहीं कर सकते। ओवरराइड की गई आधार विधि आभासी, सार या ओवरराइड होनी चाहिए।

तो 'नया' कीवर्ड आपको गैर-आभासी और स्थिर तरीकों से 'ओवरराइड' करने की अनुमति देने के लिए आवश्यक है।


4
मैं सिर्फ अपना नमूना चलाता हूं .. यह "नया", सही निर्दिष्ट नहीं करने पर भी ओवरराइड करेगा?
माइकल सिंक

2
@MichaelSync बिल्कुल, तो हमें नए कीवर्ड का उल्लेख करने की आवश्यकता क्यों है?
जूमइन

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

1
-1 -> इसकी बिल्कुल आवश्यकता नहीं है - व्यवहार समान होगा। एक नौसिखिया के newबारे में बहुत उलझन में है कि क्या है, लेकिन मुझे लगता है कि यह शाब्दिक रूप से केवल पठनीयता के लिए है - कंपाइलर बस आपको चेतावनी दे रहा है कि जब आप बेस के रूप में एक ही नाम की व्युत्पन्न वर्ग विधि कहते हैं, तो आपको बेस क्लास की विधि नहीं मिलेगी जो आप कर सकते हैं सोचो .... यह विचित्र है ... विशुद्ध रूप से पठनीयता के लिए?
डॉन चीडल

1
पूर्णता के लिए: यदि ए और बी दोनों वर्ग एक इंटरफ़ेस IMyInterfaceको लागू करते हैं, तो व्युत्पन्न वर्ग पर कार्यान्वयन को बुलाया जाएगा। इस प्रकार IMyInterface c = new B()बी वर्ग के कार्यान्वयन को कहेंगे। यदि केवल एक वर्ग इंटरफ़ेस को लागू करता है, तो जिस कक्षा से यह लागू होता है, वह विधि कहलाएगी।
नलियस

61

नहीं, यह वास्तव में "नया" नहीं है (दंड को क्षमा करें)। यह मूल रूप से एक विधि "छिपाने" के लिए उपयोग किया जाता है। अर्थात:

public class Base
{
   public virtual void Method(){}
}

public class Derived : Base
{
   public new void Method(){}
}

यदि आप ऐसा करते हैं:

Base b = new Derived();
b.Method();

बेस में विधि वह है जिसे बुलाया जाएगा, न कि व्युत्पन्न में।

कुछ और जानकारी: http://www.akadia.com/services/dotnet_polymorphism.html

अपना संपादन पुनः करें: मैंने जो उदाहरण दिया है, यदि आप "नया" का उपयोग करने के बजाय "ओवरराइड" करते हैं तो जब आप b.Method () कहते हैं; व्युत्पन्न वर्ग की विधि को बहुरूपता के कारण कहा जाएगा।


सार्वजनिक वर्ग का आधार {सार्वजनिक आभासी शून्य विधि () {कंसोल.ट्राइटलाइन ("बेस"); }} सार्वजनिक वर्ग व्युत्पन्न: बेस {सार्वजनिक शून्य विधि () {कंसोल। वाइटलाइन ("व्युत्पन्न"); }} आधार b = नया व्युत्पन्न (); b.Method (); मुझे "आधार" मिला .. यदि मैं व्युत्पन्न वर्ग में "नया" जोड़ता हूं, तो मुझे अभी भी "आधार" मिलता है ..
माइकल सिंक

@michael विधि अभी भी आभासी है
Rune FS

@MichaelSync: आपको उस कोड के साथ एक चेतावनी देखनी चाहिए; चेतावनी व्युत्पन्न।मेथोड () 'विरासत में मिले सदस्य' बेस.मेथोड () 'को छुपाता है। वर्तमान सदस्य को उस कार्यान्वयन को ओवरराइड करने के लिए, ओवरराइड कीवर्ड जोड़ें। अन्यथा नया कीवर्ड जोड़ें।
क्रिस्टोफर मैकएटकी

2
@MichaelSync यदि "ओवरराइड" शब्द को छोड़ दिया जाए, तो डिफ़ॉल्ट व्यवहार "नया" है। तो यह तथ्य कि आप नए शब्द को छोड़ रहे हैं कोई फर्क नहीं पड़ता।
BFree

1
हाँ। यही मैं भी सोचता हूं। निश्चित नहीं है कि क्यों C # "नया" कीवर्ड जोड़ा गया है .. यह सिर्फ चेतावनी को गायब करने के लिए है .. stackoverflow.com/questions/8502661/…
माइकल सिंक

22

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

ध्यान रखें कि "नया" सदस्य बनाना बहुरूपी नहीं है। यदि आप ऑब्जेक्ट को आधार प्रकार में रखते हैं, तो यह व्युत्पन्न प्रकार के सदस्य का उपयोग नहीं करेगा।

यदि आपके पास आधार वर्ग है:

public class BaseClass
{
    public void DoSomething() { }
}

और फिर व्युत्पन्न वर्ग:

public class DerivedType : BaseClass
{
    public new void DoSomething() {}

}

यदि आप एक प्रकार की घोषणा करते हैं DerivedTypeऔर फिर इसे डालते हैं, तो विधि DoSomething()बहुरूपी नहीं है, इसे आधार वर्ग विधि कहेंगे, न कि व्युत्पन्न।

BaseClass t = new DerivedType();
t.DoSomething();// Calls the "DoSomething()" method of the base class.

1
यह बेस क्लास से विधि को कॉल करेगा यहां तक ​​कि आप डेरेवोटाइप से "नया" भी हटा देंगे ..
माइकल सिंक

2
मुझे लगता है कि यह आपका दूसरा पैराग्राफ नाखून है। जब एक बेस क्लास संदर्भ से कॉल के साथ काम करते हैं , तो "नया" पॉलीमॉर्फिक नहीं है ... अर्थात। जब आप कॉल करते हैं तो आपको वही मिलता है जो आप निर्दिष्ट करते हैं। "ओवरराइड" बहुरूपी है ... अर्थात। आपको वही मिलता है जो वर्ग पदानुक्रम निर्दिष्ट करता है।
जोनाथन रेनहार्ट

यह कैसे इतना अस्पष्ट परिभाषित किया गया है? एक नौसिखिया के लिए बहुत निराशा होती है। और नहीं, इसका बहुरूपता से कोई लेना-देना नहीं है - इसका ठीक वैसा ही व्यवहार है जैसा overrideकि विधि हस्ताक्षर में नहीं है
डॉन चीडल

किस बात से छिपा है? यह निश्चित रूप से नहीं हो सकता है कि newआधार प्रकार को व्युत्पन्न प्रकार से छुपाता है, क्योंकि क्या आप हमेशा base.<type>नोटेशन का उपयोग करके आधार प्रकार तक नहीं पहुंच सकते हैं ?
वह वाइजग्य

@that Kindguy यह इस अर्थ में "छिपा हुआ" है कि आपके कोड में व्युत्पन्न वर्ग का उपयोग करते समय आधार विधि नहीं कहा जाएगा। इसे अभी भी आंतरिक रूप से उपयोग करने के लिए कहा जा सकता है base.<method>, और बाहरी रूप से भी कहा जा सकता है यदि आप अपने कोड में आधार प्रकार के लिए आते हैं। इसे "छिपाने" की तुलना में आधार पद्धति को "ओवरराइडिंग" के रूप में समझना तकनीकी रूप से अधिक सटीक है।
दान हर्बर्ट

7

डॉक्स से:

यदि व्युत्पन्न वर्ग में विधि नए खोजशब्द से पहले है, तो विधि को आधार वर्ग में विधि के स्वतंत्र होने के रूप में परिभाषित किया गया है।

व्यवहार में इसका क्या अर्थ है:

यदि आपको किसी अन्य वर्ग से विरासत में मिला है और आपके पास एक ऐसा तरीका है जो उसी हस्ताक्षर को साझा करता है जिसे आप इसे 'नया' के रूप में परिभाषित कर सकते हैं ताकि यह मूल वर्ग से स्वतंत्र हो। इसका अर्थ है कि यदि आपके पास 'मूल' वर्ग का संदर्भ है तो उस क्रियान्वयन को क्रियान्वित किया जाएगा, यदि आपके पास बाल वर्ग का संदर्भ है तो उस क्रियान्वयन को निष्पादित किया जाएगा।

व्यक्तिगत रूप से मैं 'नए' कीवर्ड से बचने की कोशिश करता हूं क्योंकि आमतौर पर इसका मतलब है कि मुझे अपनी कक्षा पदानुक्रम गलत लगी है, लेकिन ऐसे समय होते हैं जब यह उपयोगी हो सकता है। एक जगह संस्करण और पीछे की संगतता के लिए है।

इसके लिए MSDN में बहुत सारी जानकारी है ।


तथ्य यह है कि इस व्यवहार होता है newवहाँ होने के साथ कुछ नहीं करना है । यह वाक्यात्मक / पठनीयता है।
डॉन चेडल

3

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


3

छोटी कहानी - इसकी आवश्यकता नहीं है, यह कोई व्यवहार नहीं बदलता है, और यह पठनीयता के लिए पूरी तरह से है।

यही कारण है कि वीएस में आप थोड़ा स्क्वीगली देखेंगे, फिर भी आपका कोड पूरी तरह से ठीक है और उम्मीद के मुताबिक चलेगा।

एक आश्चर्य करने के लिए किया है, तो यह वास्तव में बनाने लायक था newकीवर्ड जब सभी इसका मतलब है कि डेवलपर के स्वीकार करते हैं "हाँ, मैं जानता हूँ कि मैं एक आधार विधि छुपा रहा हूँ, हाँ मैं जानता हूँ कि मैं से संबंधित कुछ भी नहीं कर रहा हूँ है virtualया overriden(बहुरूपता) - मैं वास्तव में इसे अपनी विधि बनाना चाहता हूं ”।

यह मेरे लिए थोड़ा विचित्र है, लेकिन शायद केवल इसलिए कि मैं एक Javaपृष्ठभूमि से आता C#हूं और विरासत और Java: के बीच यह मूलभूत अंतर है Java, जब तक कि निर्दिष्ट नहीं किया जाता है, तब तक विधियां डिफ़ॉल्ट रूप से आभासी होती हैं final। में C#द्वारा निर्दिष्ट जब तक, विधियों डिफ़ॉल्ट रूप से अंतिम / ठोस हैं virtual


1

से MSDN :

बेस क्लास से विरासत में प्राप्त सदस्य को स्पष्ट रूप से छिपाने के लिए नए संशोधक का उपयोग करें। विरासत में दिए गए सदस्य को छिपाने के लिए, उसे उसी नाम का उपयोग करके व्युत्पन्न वर्ग में घोषित करें, और नए संशोधक के साथ संशोधित करें।


0

इस गोत्र से सावधान रहें।
आपके पास एक इंटरफ़ेस में परिभाषित विधि है जो एक बेस क्लास में कार्यान्वित की जाती है। आप तब एक व्युत्पन्न वर्ग बनाते हैं जो इंटरफ़ेस की विधि को छिपाता है, लेकिन विशेष रूप से इंटरफ़ेस को लागू करने के रूप में व्युत्पन्न वर्ग की घोषणा नहीं करता है। यदि आप फिर इंटरफ़ेस के संदर्भ में विधि को कॉल करते हैं, तो बेस क्लास की विधि को बुलाया जाएगा। हालाँकि, यदि आपका व्युत्पन्न वर्ग विशेष रूप से इंटरफ़ेस को लागू करता है, तो इसकी विधि को जो भी प्रकार का संदर्भ कहा जाता है, उपयोग किया जाएगा।

interface IMethodToHide
{
    string MethodToHide();
}

class BaseWithMethodToHide : IMethodToHide
{
    public string MethodToHide()
    {
        return "BaseWithMethodToHide";
    }
}

class DerivedNotImplementingInterface   : BaseWithMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedNotImplementingInterface";
    }
}

class DerivedImplementingInterface : BaseWithMethodToHide, IMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedImplementingInterface";
    }
}

class Program
{
    static void Main()
    {
        var oNoI = new DerivedNotImplementingInterface();
        IMethodToHide ioNoI = new DerivedNotImplementingInterface();

        Console.WriteLine("reference to the object type DerivedNotImplementingInterface calls the method in the class " 
            + oNoI.MethodToHide());
        // calls DerivedNotImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedNotImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioNoI.MethodToHide());
        // calls BaseWithMethodToHide.MethodToHide()
        Console.ReadLine();

        var oI = new DerivedImplementingInterface();
        IMethodToHide ioI = new DerivedImplementingInterface();

        Console.WriteLine("reference to the object type DerivedImplementingInterface calls the method in the class " 
            + oI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.ReadLine();

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