2011-03-08 13 views
6

में ऑब्जेक्ट्स की एक सूची को डाउनकास्टिंग करना मैं ऑब्जेक्ट्स की सूची कैसे घटा सकता हूं ताकि सूची में से प्रत्येक ऑब्जेक्ट व्युत्पन्न कक्षा के ऑब्जेक्ट पर डाउनकास्ट हो?सी #

यह परिदृश्य है।

मैं आधार मदों की एक List के साथ एक आधार वर्ग है, और इसे से इनहेरिट दो वर्गों:

public class BaseClass 
{ 
    public List<BaseItem> items; 
    protected BaseClass() 
    { 
     // some code to build list of items 
    } 
} 
public class DerivedClass : BaseClass 
{ 
    public DerivedClass : base() {} 
} 
public class AnotherDerivedClass : BaseClass 
{ 
    public AnotherDerivedClass : base() {} 
} 

public class BaseItem {} 
public class DerivedItem : BaseItem {} 
public class AnotherDerivedItem : BaseItem {} 

विचार कोड आइटमों की सूची बनाने की जरूरत नकल करने की जरूरत नहीं है। BaseItem में मेरी सभी आवश्यक सामग्री है, और मैं हमेशा व्युत्पन्न वस्तुओं में से एक को BaseItem घटा सकता हूं।

समस्या तब उत्पन्न होती है जब मेरे पास उनकी सूची होती है। ListBaseItemBaseClass में घोषित किया गया है क्योंकि सभी व्युत्पन्न कक्षाओं में यह होना चाहिए। लेकिन रनटाइम पर इसे एक्सेस करते समय मैं व्युत्पन्न कक्षा में डाउनकास्ट करने में सक्षम नहीं लग सकता।

+0

आप शायद इंटरफेस करने के लिए की तलाश में किया जाना चाहिए। –

+0

या एएस और आईएस कीवर्ड। – ThatBlairGuy

+0

या बोग मानक बहुरूपता: बेस क्लास में आभासी विधियां, जिन्हें आप व्युत्पन्न कक्षाओं में ओवरराइड करते हैं। कोई डाउनकास्टिंग आवश्यक नहीं है क्योंकि आप ओवरराइड विधियों को कॉल करने के लिए बेस क्लास प्रकार का उपयोग करते हैं। – Polyfun

उत्तर

5

का प्रयोग LINQ:

var baseList = new List<BaseClass>(); 
    var derivedList = baseList.Cast<DerivedClass>(); 

नोट: आमतौर पर खिन्न करने के बाद एक 'गंध' है और पता चलता है कि वंशानुगत पदानुक्रम गलत है, या गलत तरीके से लागू किया है। बेस क्लास रखने का विचार यह है कि आप सभी उप-वर्गों को सुपरक्लास के रूप में व्यक्तिगत उप-वर्ग प्रकारों को कम किए बिना इलाज कर सकते हैं।

Cast के बजाय आप OfType का उपयोग सुपरक्लास के संग्रह से कुछ व्युत्पन्न कक्षाओं में 'मछली बाहर' करने के लिए कर सकते हैं। लेकिन फिर, ऐसा करने की कोई आवश्यकता नहीं होनी चाहिए।

अपने आप से पूछें, आपको उप-वर्ग क्यों होना चाहिए - शायद आपको बेस क्लास में कुछ कार्यक्षमता को स्थानांतरित करने की आवश्यकता है?

+0

यह वही करता है जो मैं पूछ रहा था। लेकिन अन्य उत्तरों और टिप्पणियां मुझे आश्चर्यचकित कर रही हैं अगर शायद मैं इस तरह की चीज पूरी तरह से करने से बच सकता हूं। – Farinha

+0

@ फ़ारन्हा - एक नोट –

+0

जोड़ा गया और मैं इस समाधान को कल रात काम कर सकता हूं ... और यह अब और नहीं है ... – Farinha

5

मेरा मानना ​​है कि आप क्या करना चाहते हैं उपयोग जेनरिक है:

public class BaseClass<T> where T: BaseItem, new() 
{ 
    public List<T> items; 
    protected BaseClass() 
    { 
     items = new List<T>(); 
     T item = new T(); 
     item.SomePropertyOfBaseItem=something; 
     items.Add(item); 
    } 
} 

public class DerivedClass: BaseClass<DerivedItem> 

यह DerivedClass में items कारण List<DerivedItem> होने के लिए होगा। where लागू करता है कि केवल BaseItem से प्राप्त होने वाले प्रकारों का उपयोग किया जा सकता है।

संपादित करें: "डाउनकास्टिंग", एक व्युत्पन्न प्रकार के लिए एक प्रकार कास्टिंग, वास्तव में आप यहां क्या करने की कोशिश कर रहे हैं। आपका इरादा यह है कि व्युत्पन्न सूची ऑब्जेक्ट डिज़ाइन द्वारा एक विशिष्ट व्युत्पन्न आइटम प्रकार का उपयोग करते हैं, और संभवतः आप अपनी व्युत्पन्न सूची कक्षा में व्युत्पन्न प्रकार की तत्काल वस्तुएं संग्रहीत करना चाहते हैं।

तो, यह जेनिक्स का उपयोग किये बिना ठीक काम कर सकता है: List<BaseItem>BaseItem से प्राप्त किसी भी आइटम को संग्रहीत करने में पूरी तरह से सक्षम है। हालांकि, व्युत्पन्न गुणों तक पहुंचने के लिए आपको इन वस्तुओं को कास्टिंग (अन्य उत्तरों में वर्णित अनुसार) का उपयोग करके सूची से संदर्भित करना होगा। लेकिन यह केवल एक वास्तविक वस्तु के लिए एक वस्तु कास्टिंग "कास्टिंग" है। जेनेरिक आपको इन वस्तुओं को सीधे दृढ़ता से टाइप की गई पहुंच प्रदान करने का एक तरीका प्रदान करता है।

मूल रूप से, किसी ऑब्जेक्ट को एक कंटेनर में संग्रहीत करना जो ऑब्जेक्ट के सुपरक्लास है, ऑब्जेक्ट के बारे में कुछ भी नहीं बदलता है - यह केवल आपके कोड को संदर्भित करने के तरीके को बदल सकता है, इसे सरल प्रकार से दिखाता है जो यह प्राप्त होता है।

+0

यहां समस्या यह है कि बेसक्लास में आइटम विशेषताएँ उपयोगी है, क्योंकि अन्यथा मैं बेस क्लास के निर्माण का निर्माण करने में सक्षम नहीं हूं। – Farinha

+0

क्यों नहीं? आपके कन्स्ट्रक्टर 'सूची ' के साथ क्या करेगा, यह 'सूची ' के साथ आसानी से नहीं कर सकता है? कंपाइलर वास्तव में 'कहां' खंड के कारण आपकी बेस क्लास में 'बेसआईटम 'की तरह' टी 'का इलाज करेगा। –

+0

बीटीडब्ल्यू - जेनेरिक, संभवतः, 1.0 से सी # के लिए सबसे उपयोगी जोड़ हैं। मुझे पता है, मुझे उन लोगों से कुछ असहमति होगी जो linq, या शायद '=' पसंद करते हैं। लेकिन जब आप कोड बना सकते हैं जो कास्टिंग का उपयोग करके वही काम करता है, तो जेनिक्स का उपयोग करके आपके कोड को अधिक पठनीय, समझदार और बग प्रतिरोधी बना देगा, जिससे आप आंतरिक सदस्यों को दृढ़ता से टाइप कर सकते हैं और मूल्यों को वापस कर सकते हैं। –

0
public class Zoo 
{ 
    public List<Animal> items; 
    protected BaseClass() 
    {   // some code to build list of items  } 
} 

public class PettingZoo : Zoo 
{ 
    public PettingZoo : base() {} 
} 

public class CatComplex : Zoo 
{ 
    public CatComplex : base() {} 
} 

public class Animal {} 
public class Sheep : Animal {} 
public class Tiger : Animal {} 

...

PettingZoo myZoo = new PettingZoo(); 
myZoo.items.Add(new Tiger()); 

PettingZoo के रूप में एक PettingZoo पशु के प्रकारों को प्रतिबंधित करना चाहिए, चिड़ियाघर के साथ परस्पर विनिमय नहीं है। इस प्रकार, यह डिज़ाइन the Liskov substitution principle विफल रहता है।

0

आप भी इस तरह आधार वर्ग के तत्वों के माध्यम से पुनरावृति और प्रत्येक तत्व खिन्न करने के लिए, LINQ का उपयोग कर सकते हैं:

var baseList = new List<BaseClass>(); 
var derivedList = new List<DerivedClass>(); 
baseList.ForEach(v => derivedList.Add((DerivedClass)v)); 

आप कास्टिंग से पहले प्रत्येक तत्व के व्युत्पन्न प्रकार की जाँच करने की जरूरत है:

var baseList = new List<BaseClass>(); 
var derivedList = new List<DerivedClass>(); 
baseList.OfType<DerivedClass>().ToList().ForEach(v => derivedList.Add(v)); 

अधिक जानकारी के लिए, निम्न आलेख पर एक नज़र डालें: