2012-02-23 19 views
7

मैंने सोचा कि मैंने यह नाखुश किया है, और फिर मैं काम पर कुछ स्रोत देखता हूं और सोच रहा हूं कि एमएसडीएन से जो कुछ मैंने पढ़ा है और जो मैं स्रोत में देख रहा हूं, उसके इतने सारे विरोधाभास क्यों हैं। ...सी # वर्चुअल और ओवरराइड कीवर्ड

मेरी समझ यह है कि वर्चुअल कीवर्ड विधि घोषणाओं में उपयोग किया जा सकता है ताकि किसी भी व्युत्पन्न कक्षाओं को इसे ओवरराइड करने की अनुमति मिल सके।

:

ओवरराइड कीवर्ड तो व्युत्पन्न वर्ग जब सुपर क्लास 'आभासी विधि को लागू करने में प्रयोग की जाने वाली

उदाहरण के लिए की आवश्यकता होगी ....:

public abstract class A 
{ 
    public virtual string GetName(); 
} 


public class B:A 
{ 

    //assume there are some defined properties. 
    public override string GetName() 
    { 
     return FirstName; 
    } 
} 

मैं कुछ प्रश्न हैं

1) क्या वर्चुअल के रूप में किसी विधि को परिभाषित करना वास्तव में आवश्यक है यदि इसका कोई कार्यान्वयन नहीं है? निश्चित रूप से वर्चुअल और ओवरराइड के उपयोग के बिना इसे उप-वर्ग में ओवरराइट किया जा सकता है?

2) यदि (1) गलत है, मैं सही सोच है कि हर आभासी विधि इसे प्रयोग उपवर्ग में अधिरोहित किया जाना चाहिए में हूँ ....

संपादित करें:

आप सही मेरे कोड रहे हैं सबसे पहले वें

public abstract class RequestHandler<TRequest, TResponse> : RequestHandler, IRequestHandler<TRequest>, IRequestHandler, IDisposable, ITypedRequestHandler 
    where TRequest : global::Agatha.Common.Request 
    where TResponse : global::Agatha.Common.Response, new() 
{ 
    protected RequestHandler(); 

    public virtual void AfterHandle(TRequest request); 
    public virtual void BeforeHandle(TRequest request); 
    public override Response CreateDefaultResponse(); 
    public TResponse CreateTypedResponse(); 
    public override Response Handle(Request request); 
    public abstract Response Handle(TRequest request); 
} 

ऊपर नहीं करता संकलक शिकायत करने के लिए कारण ...

+0

आपका उदाहरण संकलित नहीं करता है ("' एगेटनाम() 'को शरीर घोषित करना चाहिए क्योंकि इसे 'सार', 'बाहरी' या 'आंशिक'' चिह्नित नहीं किया गया है)। – dtb

+0

क्या आपकी कक्षा ए संकलन अपने अनुपस्थित सार को नोट करेगा? – V4Vendetta

+0

निश्चित रूप से कक्षा ए में विधि सार्वजनिक सार स्ट्रिंग GetName() होना चाहिए; – Vedran

उत्तर

10

: संकलन नहीं होगा ... मैं जानना क्यों चाहते हैं .... मैं अपने जवाब uinderstand लेकिन फिर मैं यह देखा ई कोड ऊपर अमान्य है। एक वर्चुअल विधि में अभी भी एक डिफ़ॉल्ट कार्यान्वयन के साथ एक शरीर होना चाहिए। जो आपने ऊपर किया है उसे करने के लिए आपको वर्चुअल के बजाय abstract कीऑर्ड का उपयोग करने की आवश्यकता होगी।

abstract का अर्थ है कि कोई विधि निकाय नहीं है लेकिन इससे प्राप्त किसी भी वर्ग को इस विधि को लागू करना होगा (जब तक कि यह सार भी न हो)।

मैं इस काफी अपने सवालों के जवाब लगता है ....

  1. यह कोई कार्यान्वयन तो यह आभासी नहीं हो सकता है, यह सार होना चाहिए है। यदि इसका कार्यान्वयन है जो कुछ भी नहीं करता है तो इसे लागू किया जाना चाहिए।

  2. वर्चुअल क्लास का पूरा बिंदु यह है कि इसमें डिफ़ॉल्ट व्यवहार है ताकि आप इसे चुन सकें कि इसे ओवरराइड करना है या नहीं। यदि यह अमूर्त था तो आपको इसे ओवरराइड करना होगा (जब तक कि आप एक और सार वर्ग नहीं ले रहे थे)।

+0

हां यह वही है जो मैंने सोचा था, लेकिन मेरे पास कुछ स्रोत है जो संकलक को शिकायत नहीं करता है ... कृपया – user559142

+0

से ऊपर संपादित करें देखें। यदि वास्तव में शरीर अस्तित्व में था, 'आभासी' के साथ यह विरासत वर्ग को विधि को लागू करने के लिए नहीं होगा। – Aphelion

+0

धन्यवाद जो समझ में आता है लेकिन मैं अभी भी उपरोक्त स्रोत के बारे में उलझन में हूं – user559142

0

ठीक है, आभासी रूप में विधि की घोषणा (और उपवर्ग में विधि ओवरराइड करने के लिए बधाई देने के लिए नहीं), आप विधि छुपा के दुनिया में प्रवेश होगी अगर आप एक ही साथ एक विधि को पेश करने थे द्वारा subclass में नाम।आप के रूप में इस प्रकार यह परिभाषित करने के लिए है:

public abstract class A 
{ 
    public virtual string GetName() 
    { 
     return null; 
    } 
} 

public class B : A 
{ 
    //assume there are some defined properties. 
    public new string GetName() 
    { 
     return FirstName; 
    } 
} 

मैं सलाह देते हैं आप सार ओवरराइड दृष्टिकोण के बारे में सोच है कि:

public abstract class A 
{ 
    public abstract string GetName() 
} 

// to override 
public class B : A 
{ 
    //assume there are some defined properties. 
    public override string GetName() 
    { 
     return FirstName; 
    } 
} 

यह काफी अलग होगा। मैं दृढ़ता से अनुशंसा करता हूं कि आप सबक्लास में सार विधि को ओवरराइड करें।

हालांकि, यहां इस विषय पर एक त्वरित रेफरी (पुराने लेकिन एक अच्छा पढ़ा) है:

http://www.akadia.com/services/dotnet_polymorphism.html

+0

यह संकलित नहीं होगा, आप एक अमूर्त विधि को छुपा नहीं सकते हैं। – softveda

+0

आह -ोक, जिस स्थिति में कक्षा ए को वर्चुअल होना चाहिए। उत्तर में संशोधन करेगा –

+0

आप वास्तव में ** ** अमूर्त विधि को ओवरराइड से बच नहीं सकते हैं। यह एक अनिवार्य है। – Tigran

2

यह चाहें कि अगर कोई कार्यान्वयन है आभासी रूप में एक विधि को परिभाषित करने के वास्तव में आवश्यक है?

आप विधि सार बना सकते हैं (यह निश्चित रूप से इसे आभासी बना देगा)।

निश्चित रूप से इसे वर्चुअल और ओवरराइड के उपयोग के बिना उप-वर्ग में ओवरराइट किया जा सकता है?

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

एक उदाहरण यह स्पष्ट कर देगा:

class B 
{ 
    public virtual void M() { Console.WriteLine("B.M") }; 
} 

class D1 : Base 
{ 
    // Hides the base method 
    public new void M() { Console.WriteLine("D1.M") }; 
} 


class D2 : Base 
{ 
    // Overrides the base method 
    public override void M() { Console.WriteLine("D2.M") }; 
} 

... 

D1 d1 = new D1(); 
d1.M(); // Prints "D1.M" 
B b1 = d1; 
b1.M(); // Prints "B.M", because D1.M doesn't override B.M 

D2 d2 = new D1(); 
d2.M(); // Prints "D2.M" 
B b2 = d2; 
b2.M(); // Also prints "D2.M", because D2.M overrides B.M 

हैं (1) गलत है, सही सोच है कि हर आभासी विधि उपवर्ग इसे प्रयोग में अधिरोहित किया जाना चाहिए में मैं कर रहा हूँ ....

नहीं, केवल तब यह सार है .. एक वर्चुअल विधि में कार्यान्वयन हो सकता है, और उसमें केस व्युत्पन्न कक्षाओं को इसे ओवरराइड करने के लिए मजबूर नहीं किया जाता है।

0

virtual की आवश्यकता polymorphism द्वारा निर्धारित है। क्या होता है जब आप new का उपयोग कर एक उपवर्ग में एक विधि को फिर से परिभाषित के बारे में सोचो:

class Parent 
{ 
    void Foo() { Console.WriteLine("Parent"); } 
    virtual void Bar { Console.WriteLine("Parent"); } 
} 

class Child : Parent 
{ 
    new void Foo() { Console.WriteLine("Child"); } // another method Foo 
    override void Bar { Console.WriteLine("Child"); } 
} 

var child = new Child(); // a Child instance 
var parent = (Parent)child; // same object, but statically typed as Parent 

c.Bar(); // prints "Child" 
p.Bar(); // again, prints "Child" -- expected virtual behavior 

c.Foo(); // prints "Child" 
p.Foo(); // but this prints "Parent"!! 

इस कारण से, से प्राप्त किया जा करने का इरादा कर रहे हैं कि वर्गों (यानी नहीं sealed) हमेशा तरीकों कि virtual के रूप में अधिरोहित जा सकता है निशान चाहिए - अन्यथा ऊपर की तरह भ्रमित रनटाइम व्यवहार होगा। यदि कोई पैरेंट कार्यान्वयन वास्तव में कुछ करता है या नहीं तो इसमें कोई फर्क नहीं पड़ता; मुद्दा यह है कि अलग-अलग व्यवहार करता है।

0

यही एक virtual और एक abstract विधि के बीच का अंतर है:

एक आभासी विधि व्युत्पन्न वर्ग द्वारा अधिरोहित जा सकता है, तो करने के लिए चुनें। एक वर्चुअल विधि में कॉल करने के लिए विरासतकर्ताओं के लिए डिफ़ॉल्ट कार्यान्वयन हो सकता है या नहीं हो सकता है, जो base कीवर्ड का उपयोग करके किया जाता है।

एक सार विधि व्युत्पन्न वर्ग द्वारा अधिरोहित किया जाना चाहिए। इसकी बाधाएं हैं:

  • इसे केवल एक अमूर्त वर्ग में परिभाषित किया जा सकता है।
  • इसमें कोई कार्यान्वयन नहीं हो सकता है, क्योंकि यह अपने व्यवहार को परिभाषित करने के लिए उत्तराधिकारी तक है।
0

1) यह वास्तव में अगर यह कोई कार्यान्वयन है आभासी रूप में एक विधि को परिभाषित करने के लिए आवश्यक है? निश्चित रूप से वर्चुअल और ओवरराइड के उपयोग के बिना इसे सबक्लास में ओवरराइट किया जा सकता है?

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

2) यदि (1) गलत है, मैं सही सोच है कि हर आभासी विधि इसे प्रयोग उपवर्ग में अधिरोहित किया जाना चाहिए में हूँ ....

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

Usauly वे abstract उपयोग करते हैं, बच्चे के लिए कठोर constrains बनाने इसलिए हर बच्चे से व्युत्पन्न आधार वर्ग की निर्दिष्ट सदस्य को लागू करना चाहिए करने के लिए।

1

1) क्या यह वास्तव में एक विधि को वर्चुअल के रूप में परिभाषित करना आवश्यक है यदि इसका कोई कार्यान्वयन नहीं है? निश्चित रूप से वर्चुअल और ओवरराइड के उपयोग के बिना इसे उप-वर्ग में ओवरराइट किया जा सकता है?

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

आप पूछ रहे थे तो चाहे virtual तरीकों जो करना एक कार्यान्वयन है virtual की घोषणा की ज़रूरत: सी # में, हां, यह आवश्यक है। जावा में, आप किसी पुरानी विधि को ओवरराइड कर सकते हैं। यह virtual कीवर्ड के साथ विशेष रूप से अनुमत होने की आवश्यकता के लिए एक सी # डिजाइन निर्णय था, ताकि प्रोग्रामर द्वारा किए जाने तक विधियों को ओवरराइड नहीं किया जा सके।

तो प्रोग्रामर virtual का उपयोग नहीं, आप अभी भी "ओवरराइड" तरीकों कर सकते हैं, new कीवर्ड के साथ द्वारा मंशा व्यक्त नहीं की है। हालांकि, यह थोड़ा अलग काम करता है।उम्मीद है कि इस कोड में मदद मिलेगी अवधारणा को वर्णन:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var baseC = new BaseClass(); 
     var extC = new ExtClass(); 
     var lazyC = new LazyClass(); 

     Console.WriteLine(baseC.NewMethod()); 
     Console.WriteLine(baseC.VirtualOverrideMethod()); 

     Console.WriteLine("---"); 

     Console.WriteLine(extC.NewMethod()); 
     Console.WriteLine(extC.VirtualOverrideMethod()); 

     Console.WriteLine("---"); 

     Console.WriteLine(((BaseClass) extC).NewMethod()); 
     Console.WriteLine(((BaseClass) extC).VirtualOverrideMethod()); // Redundant typecast 

     Console.WriteLine("---"); 

     Console.WriteLine(lazyC.VirtualOverrideMethod()); 

     Console.ReadKey(); 
    } 

    public class BaseClass 
    { 
     public BaseClass() 
     { 

     } 

     public string NewMethod() 
     { 
      return "NewMethod of BaseClass"; 
     } 

     public virtual string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of BaseClass"; 
     } 
    } 

    class ExtClass : BaseClass 
    { 
     public new string NewMethod() 
     { 
      return "NewMethod of ExtClass"; 
     } 

     public override string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of ExtClass"; 
     } 
    } 

    class LazyClass : BaseClass 
    { 
    } 
} 

आउटपुट:

NewMethod of BaseClass 
VirtualOverrideMethod of BaseClass 
--- 
NewMethod of ExtClass 
VirtualOverrideMethod of ExtClass 
--- 
NewMethod of BaseClass 
VirtualOverrideMethod of ExtClass 
--- 
VirtualOverrideMethod of BaseClass 

2) यदि (1) गलत है, मैं सही सोच है कि हर आभासी विधि में अधिरोहित किया जाना चाहिए में हूँ इसका उपयोग कर subclass ....

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

ऊपर नहीं करता संकलक शिकायत करने के लिए कारण ...

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

class ExtClass : BaseClass 
    { 
     public new string NewMethod() 
     { 
      return "NewMethod of ExtClass"; 
     } 

     public override string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of ExtClass"; 
     } 
    } 

रहे हैं:

class ExtClass : BaseClass 
    { 
     public new string NewMethod() 
     { 
      return "NewMethod of ExtClass"; 
     } 

     public override string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of ExtClass"; 
     } 
    } 

मैं:

error CS0501: 'OverrideTest.Program.ExtClass.VirtualOverrideMethod()' must declare a body because it is not marked abstract, extern, or partial 

विजुअल स्टूडियो 2010 में एक ही से मेरी BaseClass की virtual विधि के लिए चला जाता है।

संबंधित मुद्दे