2012-06-26 10 views
11

के साथ व्युत्पन्न प्रकार को मूल सार वर्ग में नहीं डाला जा सकता है मेरे पास एक साधारण फैक्ट्री विधि है जो प्रदान किए गए सामान्य प्रकार पैरामीटर के आधार पर एक ठोस कार्यान्वयन उदाहरण प्रदान करती है। यदि कंक्रीट क्लास एक सामान्य अमूर्त बेस क्लास से एक प्रकार पैरामीटर के साथ प्राप्त होता है तो मैं उन्हें नहीं डाल सकता। संकलक मुझे Error 2 Cannot convert type 'Car' to 'VehicleBase<T>' बताता है। यह ठीक काम करता है अगर मैं एक ही टाइप पैरामीटर के साथ एक इंटरफ़ेस के लिए अमूर्त कक्षा को प्रतिस्थापित करता हूं, या यदि मैं अमूर्त वर्ग से सामान्य प्रकार पैरामीटर को हटा देता हूं।टाइप पैरामीटर

interface IWheel 
{ 
} 

class CarWheel : IWheel 
{ 
} 

abstract class VehicleBase<T> 
{ 
} 

class Car : VehicleBase<CarWheel> 
{ 
} 

class VehicleFactory 
{ 
    public static VehicleBase<T> GetNew<T>() 
    { 
     if (typeof(T) == typeof(CarWheel)) 
     { 
      return (VehicleBase<T>)new Car(); 
     } 
     else 
     { 
      throw new NotSupportedException(); 
     } 
    } 
} 

यह (VehicleBase<T>)new Car() पर संकलित करने में विफल रहता है। क्या यह एक कंपाइलर दोष है, या यह अलग-अलग वर्गों और इंटरफेस को टाइप पैरामीटर के साथ अलग-अलग इलाज करने का एक जानबूझकर डिजाइन निर्णय हो सकता है?

समाधान के लिए मैं हमेशा अमूर्त वर्ग एक अंतरफलक को लागू करने और मेरी कारखाने विधि के लिए वापसी मान के रूप में उपयोग कर सकते हैं, लेकिन मैं अभी भी पता करने के लिए क्यों इस व्यवहार हो रहा है करना चाहते हैं।

उत्तर

5

यह न तो एक संकलक दोष है और न ही एक विचार निर्णय है। सामान्य वर्गों पर प्रकार पैरामीटर, neither covariant nor contravariant हैं यानी एक ही सामान्य वर्ग के विशेषज्ञताओं के बीच कोई विरासत कोई संबंध है। दस्तावेज़ों से:

.NET Framework संस्करण 4 में, प्रकार प्रकार पैरामीटर जेनेरिक इंटरफ़ेस और जेनेरिक प्रतिनिधि प्रकारों तक सीमित हैं।

जिसका मतलब है कि निम्नलिखित कोड, संकलन होगा, क्योंकि यह एक अंतरफलक के बजाय का उपयोग करता है एक अमूर्त वर्ग के:

interface IWheel 
{ 
} 

class CarWheel : IWheel 
{ 
} 

interface IVehicleBase<T> 
{ 
} 

class Car : IVehicleBase<CarWheel> 
{ 
} 

class VehicleFactory 
{ 
    public static IVehicleBase<T> GetNew<T>() 
    { 
     if (typeof(T) == typeof(CarWheel)) 
     { 
      return (IVehicleBase<T>)new Car(); 
     } 
     else 
     { 
      throw new NotSupportedException(); 
     } 
    } 
} 

चेक अधिक जानकारी और उदाहरण के लिए "Covariance and Contravariance in Generics"।

वहाँ भी है अधिक जानकारी के साथ सी # पूछे जाने वाले प्रश्न ब्लॉग पर एक Covariance and Contravariance FAQ, और Eric Lippert द्वारा विषय

+0

यह वह समाधान है जिसका मैंने उपयोग किया था। इंटरफेस/प्रतिनिधियों में भिन्नता के बारे में मुझे याद दिलाने के लिए धन्यवाद - यह समझ में आता है और मेरे प्रश्न का उत्तर देता है। – dahvyd

+0

मुझे याद दिलाने के लिए धन्यवाद। भूलना बहुत आसान है जब आपको दरवाजे से कुछ कोड प्राप्त करना होगा –

9

साध्य नहीं है यही कारण है, क्योंकि सामान्य कोड (समान आईएल के साथ) हर संभव T के लिए काम करने की जरूरत है, और कुछ नहीं कहना है कि वहाँ Car : VehicleBase<float>, उदाहरण के लिए। कंपाइलर इस तथ्य का अधिक विश्लेषण नहीं करता है कि if चेक करता है कि TCarWheel है - स्थिर जांचकर्ता प्रत्येक कथन अलग-अलग का इलाज करता है, यह शर्तों के कारण और प्रभाव को समझने की कोशिश नहीं करता है।

, यह बाध्य करने के लिए बीच में object लिए डाली:

return (VehicleBase<T>)(object)new Car(); 

हालांकि! आपका दृष्टिकोण वास्तव में "जेनेरिक" नहीं है।

+0

उचित लगता है पर एक 11-part series!, लेकिन अगर मैं एक इंटरफ़ेस का उपयोग क्यों क्या अंतर है? यही वह है जो मुझे समझ में नहीं आता है। – dahvyd

+0

यह सिर्फ इतना नहीं है कि यह साबित नहीं है। केवल जेनेरिक इंटरफेस में वेरिएंट प्रकार हो सकते हैं। यह कोड तब भी काम नहीं करेगा जब आपने उचित प्रकार की बाधाओं को निर्दिष्ट किया है –

3

यह काम करने के लिए लगता है:

return new Car() as VehicleBase<T>; 

मेरे अनुमान कारण है कि यह उस तरह से है:
VehicleBase<T> के जेनेरिक प्रकार उदाहरणों के रूप में संबंधित नहीं हैं, यह साबित नहीं किया जा सकता है कि उन्हें कास्टिंग काम कर सकता था:

enter image description here

तो T प्रकार Blah की है, कलाकारों से काम नहीं होगा। आप वापस वस्तु और उसके बाद अन्य शाखा लेने के लिए नहीं जा सकते (वहाँ सब के बाद सी # में कोई एकाधिक वंशानुक्रम है)।

इसे वापस object पर कास्ट करके, आप फिर से संभावना खोल रहे हैं कि कलाकार काम कर सकता है, क्योंकि VehicleBase<CarWheel> पर अभी भी पथ हो सकता है। एक इंटरफेस, ज़ाहिर है, कहीं भीobject नीचे इस पेड़ में भी दिखाई दे सकता है, ताकि काम करना चाहिए,।