C #: रिटर्न प्रकार ओवरराइड करना


81

क्या C # में रिटर्न प्रकार को ओवरराइड करने का कोई तरीका है? यदि हां, तो कैसे और क्यों नहीं और इसे करने का अनुशंसित तरीका क्या है?

मेरा मामला यह है कि मेरे पास एक सार आधार वर्ग और उस के वंशजों के साथ एक इंटरफ़ेस है। मैं ऐसा करना चाहूंगा (ठीक है, वास्तव में नहीं, लेकिन एक उदाहरण के रूप में!):

public interface Animal
{
   Poo Excrement { get; }
}

public class AnimalBase
{
   public virtual Poo Excrement { get { return new Poo(); } }
}

public class Dog
{
  // No override, just return normal poo like normal animal
}

public class Cat
{
  public override RadioactivePoo Excrement { get { return new RadioActivePoo(); } }
}

RadioactivePooसे विरासत में मिला Poo

इसे चाहने का मेरा कारण यह है कि जो लोग Catवस्तुओं का उपयोग करते Excrementहैं वे संपत्ति का उपयोग बिना डाले कर सकते हैंPoo में RadioactivePooजबकि उदाहरण के लिए Catअभी भी एक का हिस्सा हो सकता Animalसूची जहाँ उपयोगकर्ताओं को जरूरी बारे में पता है या उनके रेडियोधर्मी पू के बारे में ध्यान नहीं हो सकता। आशा है कि समझ में आया ...

जहाँ तक मैं देख सकता हूँ संकलक इसे कम से कम अनुमति नहीं देता है। इसलिए मुझे लगता है कि यह असंभव है। लेकिन आप इसके समाधान के रूप में क्या सलाह देंगे?


2
जेनरिक के बारे में क्या? क्या वे मदद नहीं करेंगे?
अर्निस लैप्स

3
क्या बिल्ली नहीं होनी चाहिए। () पुए के रूप में केवल रेडियोएक्टिविवू की वापसी और उदाहरण? आपके पास एक सामान्य इंटरफ़ेस है, इसका उपयोग करें। (और
हिस्टेरिकल

1
मैं भी उदाहरण के लिए धन्यवाद कहना चाहता हूं: @goodgai नीचे सार पू बनाने का सुझाव दे रहा है - मुझे आश्चर्य है कि मैं इसे गैर-प्रोग्रामर को कैसे समझा सकता हूं ...
पाओलो टेडेस्को

1
@ कोनराड: अगर मैं सिर्फ उस शानदार टिप्पणी पर हंसना चाहूं, तो थोड़ा अनिश्चित हो सकता है , या अगर मुझे यह भी पूछना चाहिए कि क्या वास्तव में यह एक बहुत भयानक कोड गंध है, जिसे इंगित किया जाना चाहिए (उस मामले में मैं इसके बारे में जानना चाहूंगा: पी)
शविश

3
मैं अपने आप में लगभग निराश हूं कि मैंने इन उदाहरणों को कितना अजीब पाया XD
Gurgadurgen

जवाबों:


24

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

मैं निम्नलिखित कारणों से कुछ मौजूदा समाधानों से खुश नहीं था:

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

मेरा समाधान

इस समाधान को उन सभी मुद्दों को दूर करना चाहिए, जिनका मैंने ऊपर उल्लेख किया है, जेनेरिक और पद्धति दोनों का उपयोग करके।

public class Poo { }
public class RadioactivePoo : Poo { }

interface IAnimal
{
    Poo Excrement { get; }
}

public class BaseAnimal<PooType> : IAnimal
    where PooType : Poo, new()
{
    Poo IAnimal.Excrement { get { return (Poo)this.Excrement; } }

    public PooType Excrement
    {
        get { return new PooType(); }
    }
}

public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }

इस समाधान के साथ आपको डॉग या कैट में कुछ भी ओवरराइड करने की आवश्यकता नहीं है! यहाँ कुछ नमूना उपयोग है:

Cat bruce = new Cat();
IAnimal bruceAsAnimal = bruce as IAnimal;
Console.WriteLine(bruce.Excrement.ToString());
Console.WriteLine(bruceAsAnimal.Excrement.ToString());

यह आउटपुट देगा: "रेडियोएक्टिवपू" दो बार जो दिखाता है कि बहुरूपता को तोड़ा नहीं गया है।

आगे की पढाई

  • स्पष्ट इंटरफ़ेस कार्यान्वयन
  • नया संशोधक । मैंने इस सरलीकृत समाधान में इसका उपयोग नहीं किया, लेकिन आपको अधिक जटिल समाधान में इसकी आवश्यकता हो सकती है। उदाहरण के लिए यदि आप बेसअनिमल के लिए एक इंटरफ़ेस बनाना चाहते हैं, तो आपको इसे "पूटाइप एक्स्सरमेंट" के अपने घोषणापत्र में उपयोग करने की आवश्यकता होगी।
  • जेनेरिक मोडिफ़ायर (कोवरियन) । फिर से मैंने इस समाधान में इसका उपयोग नहीं किया, लेकिन यदि आप MyType<Poo>IAnimal MyType<PooType>से वापसी और BaseAnimal से वापसी की तरह कुछ करना चाहते हैं , तो आपको दोनों के बीच कास्ट करने में सक्षम होने के लिए इसका उपयोग करने की आवश्यकता होगी।

6
यार, यह सुपर कूल हो सकता है। मेरे पास इस समय और अधिक विश्लेषण करने का समय नहीं है, लेकिन ऐसा लगता है कि आप इसे प्राप्त कर सकते हैं, और यदि आपने इसे क्रैक किया है, तो उच्च पांच और साझा करने के लिए धन्यवाद। दुर्भाग्य से यह is पू ’और re एक्स्रीमेंट’ व्यवसाय एक बड़ी व्याकुलता है।
निकोलस पीटरसन

1
मुझे लगता है कि मुझे संबंधित समस्या का हल मिल गया, जहां एक विधि को विरासत में वापस लौटना पड़ता है - यानी 'डॉग' में एक विधि जो 'एनिमल' से विरासत में मिली थी, फिर भी डॉग (यह) नहीं, बल्कि एनिमल है। इसका विस्तार विधियों के साथ किया जाता है, जब मैं इसे प्राप्त करता हूं तो मैं यहां साझा कर सकता हूं।
निकोलस पीटरसन

प्रकार सुरक्षा के बारे में दोनों bruce.Excement और bruceAsAnimal.Excrement प्रकार रेडियोधर्मीPoo होगा?
एंथिस किवरानग्लू

@AnestisKivranoglou हाँ दोनों रेडियोधर्मी प्रकार के होंगे
डकैती

1
मैं 48 घंटे के लिए एसओ जुताई कर रहा हूं, और इस जवाब ने इसे फटा दिया है। और मैं ऐसा था ... "यार, यह सुपर कूल हो सकता है।"
मार्टिन हैनसेन लेनोक्स

50

एक सामान्य आधार वर्ग के बारे में क्या?

public class Poo { }
public class RadioactivePoo : Poo { }

public class BaseAnimal<PooType> 
    where PooType : Poo, new() {
    PooType Excrement {
        get { return new PooType(); }
    }
}

public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }

संपादित करें : एक नया समाधान, विस्तार विधियों और एक मार्कर इंटरफ़ेस का उपयोग कर ...

public class Poo { }
public class RadioactivePoo : Poo { }

// just a marker interface, to get the poo type
public interface IPooProvider<PooType> { }

// Extension method to get the correct type of excrement
public static class IPooProviderExtension {
    public static PooType StronglyTypedExcrement<PooType>(
        this IPooProvider<PooType> iPooProvider) 
        where PooType : Poo {
        BaseAnimal animal = iPooProvider as BaseAnimal;
        if (null == animal) {
            throw new InvalidArgumentException("iPooProvider must be a BaseAnimal.");
        }
        return (PooType)animal.Excrement;
    }
}

public class BaseAnimal {
    public virtual Poo Excrement {
        get { return new Poo(); }
    }
}

public class Dog : BaseAnimal, IPooProvider<Poo> { }

public class Cat : BaseAnimal, IPooProvider<RadioactivePoo> {
    public override Poo Excrement {
        get { return new RadioactivePoo(); }
    }
}

class Program { 
    static void Main(string[] args) {
        Dog dog = new Dog();
        Poo dogPoo = dog.Excrement;

        Cat cat = new Cat();
        RadioactivePoo catPoo = cat.StronglyTypedExcrement();
    }
}

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

सेकंड EDIT @Svish: मैंने यह पता लगाने के लिए कोड को संशोधित किया कि एक्सटेंशन विधि किसी भी तरह से लागू नहीं हो रही है जो इस तथ्य iPooProviderसे विरासत में मिली है BaseAnimal। "इससे भी अधिक दृढ़ता से टाइप किए गए" से आपका क्या अभिप्राय है?


बस यही सोच रहा था।
डॉक्टर जोन्स

9
क्या आप कुत्ते और बिल्ली के बीच बहुरूपता पर बाहर नहीं निकलते हैं?
almog.ori

क्या होगा अगर वहाँ अन्य प्रकार आप भी ओवरराइड करना चाहते हैं? आप तकनीकी रूप से पूरे प्रकार के तर्कों के साथ समाप्त हो सकते हैं। जो मुझे लगता है कि मुझे गुस्सा आ गया होगा ... लेकिन हां, यह एक समाधान है।
सविश

@ सविश: मुझे लगता है कि एक बार ऐसा होता है, यह निर्भरता इंजेक्शन ढांचे का उपयोग करने का समय है।
ब्रायन

स्ट्रॉन्गलीटेप्ड एक्सक्रिमेंट पद्धति कैसे जानती है कि iPooProvider एक BaseAnimal है? क्या यह सिर्फ अनुमान है? या यह कुछ ऐसा है जिसे मैं नहीं देखता हूं? क्या उस विधि को और भी अधिक मजबूती से टाइप करना संभव होगा?
सविश

32

इसे रिटर्न टाइप कोवरियन कहा जाता है और कुछ लोगों की इच्छा के बावजूद सामान्य रूप से C # या .NET में समर्थित नहीं है

मैं जो करूंगा वही हस्ताक्षर रखूंगा लेकिन ENSUREव्युत्पन्न वर्ग के लिए एक अतिरिक्त खंड जोड़ूंगा जिसमें मैं यह सुनिश्चित करता हूं कि यह एक रिटर्न देता है RadioActivePoo। तो, संक्षेप में, मैं अनुबंध द्वारा डिजाइन के माध्यम से करूँगा जो मैं सिंटैक्स के माध्यम से नहीं कर सकता।

दूसरों को इसके बजाय नकली बनाना पसंद करते हैं । यह ठीक है, मुझे लगता है, लेकिन मैं कोड की "बुनियादी ढांचे" को कम करना चाहता हूं। यदि कोड के शब्दार्थ पर्याप्त रूप से स्पष्ट हैं, तो मैं खुश हूं, और अनुबंध द्वारा डिजाइन मुझे यह हासिल करने देता है, हालांकि यह एक समयबद्ध तंत्र नहीं है।

जेनरिक के लिए वही, जो अन्य उत्तर सुझाते हैं। मैं रेडियोधर्मी पू को वापस करने से बेहतर कारण के लिए उनका उपयोग करूंगा - लेकिन यह सिर्फ मैं ही हूं।


ENSURE क्लॉज क्या है? वह कैसे काम करेगा? यह .Net में एक विशेषता है
सविश

1
.Net में और .Net 4.0 के कोड कॉन्ट्रैक्ट्स को देखने से पहले, मैं ENSURE (x) क्लॉज़ को केवल "Debug.Assert (x)" लिखता हूं। आगे के संदर्भ के लिए उदाहरण के लिए देखें archive.eiffel.com/doc/manuals/technology/contract/page.html या उन्मुख सॉफ्टवेयर निर्माण, 2 संस्करण, बर्ट्रेंड मेयेर (1994) अध्याय 11. द्वारा वस्तु
डैनियल Daranas

5
"मैं उन्हें केवल रेडियोधर्मी पू को वापस करने से बेहतर कारण के लिए उपयोग करूंगा - लेकिन यह सिर्फ मेरे लिए है" पसंदीदा पसंदीदा उद्धरणों की मेरी सूची में है :)
डैनियल डाराना

9

यह विकल्प भी है (स्पष्ट इंटरफ़ेस-कार्यान्वयन)

public class Cat:Animal
{
  Poo Animal.Excrement { get { return Excrement; } }
  public RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}

आप बिल्ली को लागू करने के लिए बेस-क्लास का उपयोग करने की क्षमता खो देते हैं, लेकिन प्लस-साइड पर, आप बिल्ली और कुत्ते के बीच बहुरूपता रखते हैं।

लेकिन मुझे संदेह है कि अतिरिक्त जटिलता इसके लायक है।


4

एक संरक्षित आभासी पद्धति को क्यों नहीं परिभाषित किया गया है जो 'एक्‍सरसाइज' बनाता है और सार्वजनिक संपत्ति को 'एक्‍सरसाइज' नॉन वर्चुअल रखता है। फिर व्युत्पन्न वर्ग आधार वर्ग के रिटर्न प्रकार को ओवरराइड कर सकते हैं।

निम्नलिखित उदाहरण में, मैं 'एक्स्रीमेंट' को गैर-आभासी बनाता हूं लेकिन व्युत्पन्न वर्गों को उचित 'पू' प्रदान करने के लिए प्रॉपर्टी एक्स्रेमेंटइम्प्ल प्रदान करता हूं। बेस क्लास कार्यान्वयन को छिपाकर व्युत्पन्न प्रकार फिर 'एक्स्रीमेंट' के रिटर्न प्रकार को ओवरराइड कर सकते हैं।

Ex:

namepace ConsoleApplication8

{
public class Poo { }

public class RadioactivePoo : Poo { }

public interface Animal
{
    Poo Excrement { get; }
}

public class AnimalBase
{
    public Poo Excrement { get { return ExcrementImpl; } }

    protected virtual Poo ExcrementImpl
    {
        get { return new Poo(); }
    }
}

public class Dog : AnimalBase
{
    // No override, just return normal poo like normal animal
}

public class Cat : AnimalBase
{
    protected override Poo ExcrementImpl
    {
        get { return new RadioactivePoo(); }
    }

    public new RadioactivePoo Excrement { get { return (RadioactivePoo)ExcrementImpl; } }
}
}

उदाहरण ने इसे समझने के लिए बहुत कठिन बना दिया। लेकिन महान कोड!
rposky

2

अगर सही गलत है तो मुझे सुधारो लेकिन पॉलीमॉर्फिज्म के पूरे बिंदु को रेडियोअक्टीव्यूप में वापस लाने में सक्षम नहीं होना चाहिए अगर यह पू से विरासत में मिला है, तो अनुबंध सार वर्ग के समान होगा लेकिन सिर्फ रेडियोएक्टिवू (वापसी)


2
आप पूरी तरह से सही हैं, लेकिन वह अतिरिक्त कलाकारों और कुछ मजबूत-टाइपिंग से बचना चाहता है, जो कि ज्यादातर जेनरिक के लिए है ...
पाओलो टेडेस्को

2

इसे इस्तेमाल करे:

namespace ClassLibrary1
{
    public interface Animal
    {   
        Poo Excrement { get; }
    }

    public class Poo
    {
    }

    public class RadioactivePoo
    {
    }

    public class AnimalBase<T>
    {   
        public virtual T Excrement
        { 
            get { return default(T); } 
        }
    }


    public class Dog : AnimalBase<Poo>
    {  
        // No override, just return normal poo like normal animal
    }

    public class Cat : AnimalBase<RadioactivePoo>
    {  
        public override RadioactivePoo Excrement 
        {
            get { return new RadioactivePoo(); } 
        }
    }
}

यहाँ एनिमल इंटरफ़ेस का क्या मतलब है? इससे कुछ भी विरासत में नहीं मिलता है।
लूट

1

मुझे लगता है कि मैंने एक ऐसा तरीका ढूंढ लिया है जो जेनरिक या एक्सटेंशन के तरीकों पर निर्भर नहीं करता है, बल्कि पद्धति को छिपाता है। यह बहुरूपता को तोड़ सकता है, हालांकि, विशेष रूप से सावधान रहें यदि आप कैट से आगे बढ़ते हैं।

मुझे उम्मीद है कि 8 महीने देर से होने के बावजूद यह पोस्ट किसी की मदद कर सकती है।

public interface Animal
{
    Poo Excrement { get; }
}

public class Poo
{
}

public class RadioActivePoo : Poo
{
}

public class AnimalBase : Animal
{
    public virtual Poo Excrement { get { return new Poo(); } }
}

public class Dog : AnimalBase
{
    // No override, just return normal poo like normal animal
}

public class CatBase : AnimalBase
{
    public override Poo Excrement { get { return new RadioActivePoo(); } }
}

public class Cat : CatBase
{
    public new RadioActivePoo Excrement { get { return (RadioActivePoo) base.Excrement; } }
}

ऐक, मन कभी नहीं। मुझे महसूस नहीं हुआ कि hjb417 ने पहले ही एक समान समाधान पोस्ट किया है। कम से कम मेरा आधार वर्ग को संशोधित करने की आवश्यकता नहीं है।
Cybis

अपने "समाधान" करता है को तोड़ने बहुरूपता, तो यह वास्तव में एक समाधान नहीं है। दूसरी ओर hjb समाधान वास्तविक समाधान है, और सुंदर स्मार्ट IMHO है।
ग्रीनल्डमैन

0

यह मदद कर सकता है अगर रेडियोएक्टिवपू पू से प्राप्त होता है और फिर जेनरिक का उपयोग करता है।


0

FYI करें। इसे स्काला में काफी आसानी से लागू किया गया है।

trait Path

trait Resource
{
    def copyTo(p: Path): Resource
}
class File extends Resource
{
    override def copyTo(p: Path): File = new File
    override def toString = "File"
}
class Directory extends Resource
{
    override def copyTo(p: Path): Directory = new Directory
    override def toString = "Directory"
}

val test: Resource = new Directory()
test.copyTo(null)

यहाँ एक जीवंत उदाहरण है जिसे आप साथ निभा सकते हैं: http://www.scalakata.com/50d0d6e7e4b0a825d655e832


0

मेरा मानना ​​है कि आपके जवाब को कोवरियन कहा जाता है।

class Program
{
    public class Poo
    {
        public virtual string Name { get{ return "Poo"; } }
    }

    public class RadioactivePoo : Poo
    {
        public override string Name { get { return "RadioactivePoo"; } }
        public string DecayPeriod { get { return "Long time"; } }
    }

    public interface IAnimal<out T> where T : Poo
    {
        T Excrement { get; }
    }

    public class Animal<T>:IAnimal<T> where T : Poo 
    {
        public T Excrement { get { return _excrement ?? (_excrement = (T) Activator.CreateInstance(typeof (T), new object[] {})); } } 
        private T _excrement;
    }

    public class Dog : Animal<Poo>{}
    public class Cat : Animal<RadioactivePoo>{}

    static void Main(string[] args)
    {
        var dog = new Dog();
        var cat = new Cat();

        IAnimal<Poo> animal1 = dog;
        IAnimal<Poo> animal2 = cat;

        Poo dogPoo = dog.Excrement;
        //RadioactivePoo dogPoo2 = dog.Excrement; // Error, dog poo is not RadioactivePoo.

        Poo catPoo = cat.Excrement;
        RadioactivePoo catPoo2 = cat.Excrement;

        Poo animal1Poo = animal1.Excrement;
        Poo animal2Poo = animal2.Excrement;
        //RadioactivePoo animal2RadioactivePoo = animal2.Excrement; // Error, IAnimal<Poo> reference do not know better.


        Console.WriteLine("Dog poo name: {0}",dogPoo.Name);
        Console.WriteLine("Cat poo name: {0}, decay period: {1}" ,catPoo.Name, catPoo2.DecayPeriod);
        Console.WriteLine("Press any key");

        var key = Console.ReadKey();
    }
}

0

आप एक वापसी का उपयोग कर सकते हैं एक इंटरफ़ेस। आपके मामले में, आई.पी.यू.

यह एक सामान्य प्रकार का उपयोग करने के लिए बेहतर है, आपके मामले में, क्योंकि आप एक टिप्पणी बेस क्लास का उपयोग कर रहे हैं।


0

निम्नलिखित कई अन्य उत्तरों के सर्वोत्तम पहलुओं के साथ-साथ आवश्यक प्रकार की संपत्ति Catहोने के प्रमुख पहलू को अनुमति देने के लिए एक तकनीक को जोड़ती है , लेकिन वापस लौटने में सक्षम होने के नाते जैसे कि हम केवल जानते हैं कि हमें इसके बजाय मिला है विशेष रूप से एExcrementRadioactivePooPooAnimalBaseCat

कॉलर्स को जेनेरिक का उपयोग करने की आवश्यकता नहीं होती है, भले ही वे कार्यान्वयन में मौजूद हों, और न ही विशेष प्राप्त करने के लिए एक अलग नाम वाले फ़ंक्शन को कॉल करने के लिए Poo

मध्यवर्ती वर्ग AnimalWithSpecialisationsकेवल Excrementसंपत्ति को सील करने के लिए कार्य करता है, इसे गैर-सार्वजनिक SpecialPooसंपत्ति के माध्यम से व्युत्पन्न वर्ग से जोड़ता है AnimalWithSpecialPoo<TPoo>जिसमें Excrementएक व्युत्पन्न रिटर्न प्रकार की संपत्ति होती है।

यदि Catएकमात्र ऐसा जानवर Pooहै, जो किसी भी तरह से विशेष है, या हम नहीं चाहते हैं कि किस प्रकार की Excrementमुख्य परिभाषित विशेषता हो Cat, मध्यवर्ती सामान्य वर्ग को पदानुक्रम में छोड़ दिया जा सकता है, तो यह Catसीधे से प्राप्त होता है AnimalWithSpecialisations, लेकिन अगर वहाँ कई अलग-अलग जानवर हैं, जिनकी प्राथमिक विशेषता यह है कि उनकी Pooकिसी न किसी तरह से विशेष है, "बॉयलरप्लेट" को मध्यवर्ती कक्षाओं में अलग करना, Catअतिरिक्त आभासी फ़ंक्शन कॉल के एक जोड़े की कीमत पर वर्ग को खुद को काफी साफ रखने में मदद करता है ।

उदाहरण कोड दिखाता है कि अधिकांश अपेक्षित संचालन "अपेक्षा के अनुरूप" काम करते हैं।

public interface IExcretePoo<out TPoo>
  where TPoo : Poo
{
  TPoo Excrement { get; }
}

public class Poo
{ }

public class RadioactivePoo : Poo
{ }

public class AnimalBase : IExcretePoo<Poo>
{
  public virtual Poo Excrement { get { return new Poo(); } }
}

public class Dog : AnimalBase
{
  // No override, just return normal poo like normal animal
}

public abstract class AnimalWithSpecialisations : AnimalBase
{
  // this class connects AnimalBase to AnimalWithSpecialPoo<TPoo>
  public sealed override Poo Excrement { get { return SpecialPoo; } }

  // if not overridden, our "special" poo turns out just to be normal animal poo...
  protected virtual Poo SpecialPoo { get { return base.Excrement; } }
}

public abstract class AnimalWithSpecialPoo<TPoo> : AnimalWithSpecialisations, IExcretePoo<TPoo>
  where TPoo : Poo
{
  sealed protected override Poo SpecialPoo { get { return Excrement; } }
  public new abstract TPoo Excrement { get; }
}

public class Cat : AnimalWithSpecialPoo<RadioactivePoo>
{
  public override RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}

class Program
{
  static void Main(string[] args)
  {
    Dog dog = new Dog();
    Poo dogPoo = dog.Excrement;

    Cat cat = new Cat();
    RadioactivePoo catPoo = cat.Excrement;

    AnimalBase animal = cat;

    Poo animalPoo = catPoo;
    animalPoo = animal.Excrement;

    AnimalWithSpecialPoo<RadioactivePoo> radioactivePooingAnimal = cat;
    RadioactivePoo radioactivePoo = radioactivePooingAnimal.Excrement;

    IExcretePoo<Poo> pooExcreter = cat; // through this interface we don't know the Poo was radioactive.
    IExcretePoo<RadioactivePoo> radioactivePooExcreter = cat; // through this interface we do.

    // we can replace these with the dog equivalents:
    animal = dog;
    animalPoo = dogPoo;
    pooExcreter = dog;

    // but we can't do:
    // radioactivePooExcreter = dog;
    // radioactivePooingAnimal = dog;
    // radioactivePoo = dogPoo;
  }

0

C # 9 हमें covariant ओवरराइड रिटर्न प्रकार प्रदान करता है। मूल रूप से: जो आप चाहते हैं वह सिर्फ काम करता है


-1

ठीक है, वास्तव में एक ठोस प्रकार वापस करना संभव है जो विरासत में दिए गए प्रकार से भिन्न होता है (यहां तक ​​कि स्थिर तरीकों के लिए), इसके लिए धन्यवाद dynamic:

public abstract class DynamicBaseClass
{
    public static dynamic Get (int id) { throw new NotImplementedException(); }
}

public abstract class BaseClass : DynamicBaseClass
{
    public static new BaseClass Get (int id) { return new BaseClass(id); }
}

public abstract class DefinitiveClass : BaseClass
{
    public static new DefinitiveClass Get (int id) { return new DefinitiveClass(id);
}

public class Test
{
    public static void Main()
    {
        var testBase = BaseClass.Get(5);
        // No cast required, IntelliSense will even tell you
        // that var is of type DefinitiveClass
        var testDefinitive = DefinitiveClass.Get(10);
    }
}

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

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