2015-12-11 7 views
9

पासिंग नीचे नमूना कोड में, क्यों कॉल ArrayMethod के लिए करता है एक genric प्रकार के लिए असफल जब मैं class बाधाएक सरणी

public interface IFoo { } 
public interface IBar : IFoo { } 

public class Test 
{ 
    public void ClassConstraintTest<T>() where T : class, IFoo 
    { 
     T[] variable = new T[0]; 
     ArrayMethod(variable); 
    } 

    public void GenericTest<T>() where T : IFoo 
    { 
     T[] variable = new T[0]; 
     ArrayMethod(variable); // Compilation error: Can't convert T[] to IFoo[] 
    } 

    public void InheritanceTest() 
    { 
     IBar[] variable = new IBar[0]; 
     ArrayMethod(variable); 
    } 

    public void ArrayMethod(IFoo[] args) { } 
} 

उत्तर

9

यह क्योंकि array covariance, यानी, इस तथ्य MySubtype[] है कि शामिल नहीं हैं MyType[] का एक उप प्रकार, केवल संदर्भ प्रकारों के लिए काम करता है। class बाधा सुनिश्चित करता है कि T एक संदर्भ प्रकार है।

(ध्यान दें कि, बीती बातों की जांच में, सरणी सहप्रसरण considered to be a bad idea है, यदि आप कर सकते हैं यह से बचने के लिए उदाहरण के लिए ArrayMethod सामान्य बनाकर या बजाय IEnumerable<IFoo> का उपयोग करके की कोशिश करें।।)

+0

एक अच्छी प्रकार की प्रणाली में एक कॉन्वेंट प्रकार होना चाहिए जिसका उपयोग सरणी के रूप में किया जा सकता है, जिनकी वस्तुओं को सरणी के भीतर पढ़ा जा सकता है, बदला जा सकता है या कॉपी किया जा सकता है। .NET और Java में ऐरे प्रकार सुरक्षित रूप से कॉन्वेंटेट फैशन में ऐसे प्रकार के रूप में उपयोग किए जा सकते हैं, और इन्हें सुरक्षित रूप से लिखने योग्य संग्रह के रूप में गैर-कॉन्वेंटेट फैशन में सुरक्षित रूप से उपयोग किया जा सकता है। शायद अलग-अलग विज्ञापित क्षमताओं के साथ, सरणी के कई प्रकार के संदर्भ होने के लिए बेहतर होता, लेकिन आईएमएचओ जो केवल कॉन्वेंट एरे कहते हैं, वे "गलती" थे, वास्तव में विकल्पों की लागत को नहीं समझते थे। – supercat

5

संक्षेप में: सरणी सहप्रसरण केवल काम करता है जब दोनों सरणी एक संदर्भ के हैं (class) प्रकार।

इसे समझने के लिए, आपको विभिन्न प्रकार के सरणी के मेमोरी लेआउट को समझना होगा। सी # में हम मूल्य सरणियों (int[], float[], DateTime[], किसी भी उपयोगकर्ता परिभाषित struct[]) जहां प्रत्येक बात सरणी के अंदर क्रमिक रूप से संग्रहीत है, और संदर्भ सरणियों (object[], string[], किसी भी उपयोगकर्ता परिभाषित class[], interface[], या delegate[]) जहां संदर्भ हो अनुक्रमिक रूप से सरणी के अंदर संग्रहीत होते हैं और ऑब्जेक्ट को स्मृति में फिट होने पर सरणी के बाहर संग्रहीत किया जाता है।

आप का अनुरोध करते हैं कि किसी भी T पर विधि काम (: class बाधा के बिना) आप सरणियों के उन दो प्रकार के दोनों के लिए अनुमति देते हैं, लेकिन संकलक एक तथ्य के लिए पता है कि किसी भी int[] (या किसी अन्य मान सरणी) नहीं है किसी भी तरह जादुई रूप से वैध IFoo[] (या कोई अन्य संदर्भ सरणी) बनने जा रहा है और रूपांतरण को रोकता है। यह तब भी होता है जब आपकी संरचना IFoo लागू करती है, IFoo[] किसी अन्य कारण से संदर्भ संदर्भ नहीं है और T[] एक मान सरणी होगी।

हालांकि, जब आप यह दर्शाते हैं कि T एक संदर्भ प्रकार (अर्थात class घोषणा) है, यह अब संभव है कि T[] एक वैध IFoo[] है क्योंकि वे दोनों संदर्भ सरणियों कर रहे हैं। तो संकलक सरणी कॉन्वर्सिस नियमों का उपयोग कर कोड को अनुमति देता है (जो राज्य आप T[] का उपयोग कर सकते हैं, जहां IFoo[] आवश्यक है क्योंकि TIFoo का उप-प्रकार है)।