2013-04-23 4 views
5

निम्नलिखित वर्गों पर विचार के साथ सार विधि:प्रबलता से टाइप किये वापसी प्रकार

public abstract class Animal 
{ 
    public abstract Animal GiveBirth(); 
} 

public class Monkey : Animal 
{ 
    public override Animal GiveBirth() 
    { 
     return new Monkey(); 
    } 
} 

public class Snake : Animal 
{ 
    public override Animal GiveBirth() 
    { 
     return new Snake(); 
    } 
} 

//That one doesnt makes sense. 
public class WeirdHuman: Animal 
{ 
    public override Animal GiveBirth() 
    { 
     return new Monkey(); 
    } 
} 

मैं overrided GiveBirth विधि की वापसी प्रकार लागू करने के लिए एक तरह से खोज कर रहा हूँ इतना है कि यह हमेशा वास्तविक वर्ग प्रकार देता है, तो यह है कि WeirdHumanMonkey को जन्म दे सकता है।

मुझे लगता है कि उत्तर सामान्य प्रकारों के बारे में है, लेकिन मैं नहीं देख सकता कि मैं यह कैसे कर सकता हूं।

अपेक्षित परिणाम के उदाहरण:

public abstract class Animal 
{ 
    public abstract /*here a way to specify concrete type*/ GiveBirth(); 
} 

public class Monkey : Animal 
{ 
    public override Monkey GiveBirth() //Must returns an actual Monkey 
    { 
     return new Monkey(); 
    } 
} 

"बिल्कुल असंभव" एक जवाब, हो सकता है अगर स्पष्ट रूप से समझाया।

उत्तर

5

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

public abstract class Animal<TBirthType> where TBirthType : Animal<TBirthType> 
{ 
    public abstract TBirthType GiveBirth(); 
} 

public class Monkey<TBirthType> : Animal<TBirthType> where TBirthType : Monkey<TBirthType> 
{ 
    public override TBirthType GiveBirth() 
    { 
     return new Monkey<Monkey>(); 
    } 
} 

वैकल्पिक रूप से, यदि आपको किसी और विरासत की आवश्यकता नहीं है, तो आप जेनेरिक बंद कर सकते हैं।

public class Monkey : Animal<Monkey> 
{ 
    public override Monkey GiveBirth() 
    { 
     return new Monkey(); 
    } 
} 

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

+0

: इन विधियों सामान्य पशु प्रकार प्रतिबंधित एक ही हो सकता है। मुझे यह निर्दिष्ट करने का कोई तरीका नहीं दिख रहा है कि सामान्य प्रकार को वास्तविक वर्ग प्रकार को लागू करना होगा। जैसे 'टी: यह' या कुछ ... – Johnny5

+0

इसका समर्थन करने वाली भाषाएं क्या हैं? – Johnny5

+0

जावा इसका समर्थन करता है। कुछ भी नहीं। नेट इसका समर्थन करता है क्योंकि सीएलआर अंतर्निहित समस्या है। उम्मीद है कि भविष्य का संस्करण समर्थन जोड़ देगा, लेकिन जैसा कि मैं इसे समझता हूं, यह इसे काम करने में काफी बदलाव करेगा। –

1

आप ऐसा कुछ कर सकते हैं, जो Animal<T> के कार्यान्वयनकर्ताओं को Animal<T> GiveBirth() विधि लागू करने के लिए मजबूर करता है जो प्रकार पैरामीटर के समान प्रकार देता है, जो स्वयं को एक प्रकार का जानवर माना जाता है।

यही नहीं है काफी आप क्या चाहते हैं, लेकिन सिर्फ इसलिए कि आप देख सकते हैं:

public abstract class Animal<T> where T: Animal<T> 
{ 
    public abstract Animal<T> GiveBirth(); 
} 

public class Monkey: Animal<Monkey> 
{ 
    public override Animal<Monkey> GiveBirth() 
    { 
     return new Monkey(); 
    } 
} 

public class Snake: Animal<Snake> 
{ 
    public override Animal<Snake> GiveBirth() 
    { 
     return new Snake(); 
    } 
} 

public class WeirdHuman: Animal<WeirdHuman> 
{ 
    public override Animal<WeirdHuman> GiveBirth() 
    { 
     return new Monkey(); // Won't compile of course. 
    } 
} 

आप public override Animal<Monkey> GiveBirth() तरीकों बाहर टिप्पणी, तो आप उस संकलक शिकायत करता है और दिखाई देगा कुछ की तरह:

त्रुटि 1 'ConsoleApplication1.Monkey' विरासत में मिला नहीं लागू करता है सार सदस्य 'ConsoleApplication1.Animal.GiveBirth()'

दुर्भाग्यवश, आपको SomeKindOfAnimal: Animal<SomeKindOfAnimal> सिंटैक्स का उपयोग करके कक्षाएं घोषित करनी होंगी, लेकिन शायद यह आपके लिए काम करेगी।

(Also see this thread.)

ओह, यह काफी नहीं है, क्योंकि यह काम आप ऐसा कर सकते हैं करता है:

public class Monkey: Animal<WeirdHuman> 
{ 
    public override Animal<WeirdHuman> GiveBirth() 
    { 
     return new WeirdHuman(); 
    } 
} 

दूसरे शब्दों में, यह प्रकार पैरामीटर रोकें पशु का एक प्रकार हो सकता है, और यह टाइप पैरामीटर के समान होने के लिए GiveBirth() के रिटर्न प्रकार को भी बाधित करता है; लेकिन यह सब कुछ करता है।कुछ मामलों में यह पर्याप्त है, लेकिन शायद आपके उद्देश्यों के लिए नहीं।

फिर भी, शायद यह दृष्टिकोण जानने के लायक है।

+0

और फिर क्या होता है जब कोई 'बंदर: पशु ' बनाता है और वास्तव में बच्चों को गड़बड़ कर देता है? – Servy

+0

@ सर्वी :) ठीक है, 'GiveBirth() 'विधि अभी भी' बंदर 'को वापस करने के लिए बाध्य है, इसलिए यह ओवरराइड GiveBirth विधि के रिटर्न प्रकारों को लागू करने के लिए *" के लिए आवश्यकता को पूरा कर रहा है ताकि यह हमेशा रिटर्न हो वास्तविक वर्ग प्रकार * "(ओपी से)। आपको यह कहने की इजाजत है कि एक बंदर एक अजीब ह्यूमन है यदि आप चाहते हैं! –

+1

लेकिन इंटरफ़ेस को लागू करने वाले वर्ग के प्रकार को वापस करने के लिए बाध्य नहीं है, बस किसी भी प्रकार का इंटरफ़ेस लागू करने वाले वर्ग को चुनता है। – Servy

1

जहां तक ​​मुझे पता है, एक वर्ग श्रेणी पदानुक्रम में इसका समर्थन करने के लिए कोई साफ तरीका नहीं है। पुनरावर्ती सामान्य प्रकार पैरामीटर का उपयोग करना उदा। यदि आप संपूर्ण पदानुक्रम को नियंत्रित, और इसलिए की तरह

public class WierdHuman<Monkey> { } 

वर्गों से इनकार कर सकते हैं क्या आप वास्तव में चाहते हैं हास्केल के typeclasses, की तरह कुछ है

public class Animal<T> where T : Animal<T> { } 

स्वीकार्य हो सकता है, जहां आप कर सकते हैं की ठोस प्रकार से अधिक सार कक्षा ही सी # में जो निकटतम आप प्राप्त कर सकते हैं वह एक सरोगेट ऑब्जेक्ट को परिभाषित करना है जो आवश्यक कार्यक्षमता लागू करता है, और फिर जहां भी आपको इसकी आवश्यकता होती है उसे पास करें।

आपके मामले में, इसका मतलब जन्म देने के लिए एक इंटरफ़ेस बनाना और प्रत्येक ठोस जानवर प्रकार के लिए इसे कार्यान्वित करना है।

आपकी विधियों को इस कार्यक्षमता की आवश्यकता होती है, फिर 'टाइपक्लास उदाहरण' के लिए अतिरिक्त पैरामीटर की आवश्यकता होती है। है यही कारण है कि मैं क्या सोचा

public interface ISpawn<T> where T : Animal 
{ 
    public T GiveBirth(); 
} 

public void Populate<T>(T parent, ISpawn<T> spawn) where T : Animal 
{ 
} 
संबंधित मुद्दे