2011-09-21 18 views
19

मान लीजिए मैं एक सामान्य विधि है:कास्टिंग CS0030 क्यों देता है, जबकि "जैसा" काम करता है?

T Foo(T x) { 
    return x; 
} 

अब तक तो अच्छा। लेकिन अगर मैं हैशटेबल हूं तो मैं कुछ खास करना चाहता हूं। (मैं जानता हूँ कि यह एक पूरी तरह से काल्पनिक उदाहरण है। Foo() एक बहुत ही रोमांचक विधि, या तो नहीं है। साथ खेलते हैं।)

if (typeof(T) == typeof(Hashtable)) { 
    var h = ((Hashtable)x); // CS0030: Cannot convert type 'T' to 'System.Collections.Hashtable' 
} 

अरे। निष्पक्ष होने के लिए, हालांकि, मैं वास्तव में यह नहीं बता सकता कि यह कानूनी सी # होना चाहिए या नहीं। खैर, अगर मैं इसे अलग तरीके से करने की कोशिश करता हूं तो क्या होगा?

if (typeof(T) == typeof(Hashtable)) { 
    var h = x as Hashtable; // works (and no, h isn't null) 
} 

यह थोड़ा अजीब है। एमएसडीएन के अनुसार, expression as Type है (अभिव्यक्ति को दो बार मूल्यांकन करने के अलावा) expression is type ? (type)expression : (type)null जैसा ही है।

यदि मैं दस्तावेज़ों से समकक्ष अभिव्यक्ति का उपयोग करने का प्रयास करता हूं तो क्या होता है?

if (typeof(T) == typeof(Hashtable)) { 
    var h = (x is Hashtable ? (Hashtable)x : (Hashtable)null); // CS0030: Cannot convert type 'T' to 'System.Collections.Hashtable' 
} 

कास्टिंग और as कि मैं देख रहा हूँ है के बीच केवल प्रलेखित अंतर "as ऑपरेटर केवल संदर्भ के रूपांतरण और मुक्केबाजी रूपांतरण करता है"। शायद मुझे यह बताना होगा कि मैं संदर्भ प्रकार का उपयोग कर रहा हूं?

T Foo(T x) where T : class { 
    var h = ((Hashtable)x); // CS0030: Cannot convert type 'T' to 'System.Collections.Hashtable' 
    return x; 
} 

क्या चल रहा है? as क्यों ठीक काम करता है, जबकि कास्टिंग भी संकलित नहीं होगा? क्या कास्ट काम करना चाहिए, या as काम नहीं करना चाहिए, या क्या कास्टिंग और as के बीच कुछ अन्य भाषा अंतर है जो मुझे मिले एमएसडीएन दस्तावेज़ों में नहीं है?

+0

मुझे पूरा यकीन है कि एमएसडीएन से उद्धृत वाक्य जेनेरिक से पहले अस्तित्व में था। –

+0

फिर भी, अगर यह सब कुछ है ... निश्चित रूप से दिलचस्प सवाल! – Blindy

+0

क्या यह एक डुप्ली है, या सिर्फ निकट से संबंधित है: http://stackoverflow.com/questions/884315/how-to-up-cast-to-a-generic-object? –

उत्तर

7

सी # में डाली ऑपरेटर कर सकते हैं:

  • बॉक्स/Unbox
  • Upcast/खिन्न
  • कॉल उपयोगकर्ता-निर्धारित रूपांतरण ऑपरेटर

as Hashtable हमेशा दूसरे का मतलब है।

बाधा के साथ मूल्य प्रकार को नष्ट करके, आप विकल्प 1 बाहर हो गया है, लेकिन यह अभी भी अस्पष्ट है।


यहाँ दो दोनों काम है कि "सर्वश्रेष्ठ" दृष्टिकोण:

Hashtable h = x as Hashtable; 
if (h != null) { 
    ... 
} 

या

if (x is Hashtable) { 
    Hashtable h = (Hashtable)(object)x; 
    ... 
} 

पहले जरूरतों केवल एक ही प्रकार परीक्षण, तो यह बहुत ही कुशल है। और जेआईटी ऑप्टिमाइज़र दूसरे को पहचानता है, और इसे पहले की तरह व्यवहार करता है (कम से कम गैर-जेनेरिक प्रकारों से निपटने पर, मुझे इस विशेष मामले के बारे में निश्चित नहीं है।)

+0

तो आप कह रहे हैं कि कास्टिंग विफल हो जाती है क्योंकि इस प्रकार रूपांतरण ऑपरेटर हो सकते हैं? यह नहीं कह रहा कि आप गलत हैं लेकिन .. संकलक पहले से ही सामान्य प्रकार जानता है कि कम से कम एक 'ऑब्जेक्ट' (ओपी में 'टी: कक्षा' भाग) है, इसलिए यदि आप ऑब्जेक्ट के अंधे को डाल सकते हैं, तो नहीं आप सामान्य प्रकार के लिए भी ऐसा करने में सक्षम हैं? – Blindy

+1

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

+0

@ ब्लिंडी: दोनों मैच होने पर डाउनकास्ट उपयोगकर्ता द्वारा परिभाषित रूपांतरण पर प्राथमिकता लेता है। और चूंकि प्रत्येक ऑब्जेक्ट 'ऑब्जेक्ट' से निकला है, इसलिए 'ऑब्जेक्ट' से एक कास्ट हमेशा डाउनकास्ट से मेल खाता है। उदाहरण के लिए, यदि यह कोड '(हैशटेबल) (ऑब्जेक्ट) x; 'के रूप में लिखा गया था, तो यह काम करेगा। –

4

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

जेनेरिक्स और कास्टिंग पर अनुभाग देखें: http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx#csharp_generics_topic5

17

बेन जवाब मूल रूप से सिर पर कील मारता है, लेकिन पर विस्तार करने के लिए है कि एक सा:

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

यह संभावित रूप से महंगा है; हमने उस सुविधा को सी # 4 में जोड़ा और यदि आप वास्तव में चाहते हैं, तो आप ऑब्जेक्ट को "डायनामिक" टाइप करने के रूप में चिह्नित कर सकते हैं और कंपाइलर का एक छोटा स्ट्रिप-डाउन संस्करण रनटाइम पर फिर से शुरू होगा और आपके लिए रूपांतरण तर्क करेगा ।

लेकिन वह महंगी चीज़ आम तौर पर लोगों को नहीं चाहिए।

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

यही कारण है कि जेनेरिक कोड में "as" की अनुमति है लेकिन जानवर नहीं हैं।

सभी ने कहा: आप लगभग निश्चित रूप से गलत कर रहे हैं। यदि आपको सामान्य कोड में एक प्रकार का परीक्षण करना है, तो आपका कोड सामान्य नहीं है। यह वास्तव में एक खराब कोड गंध है।

+3

एक उदाहरण जोड़ने के लिए जहां यह कोड गंध नहीं हो सकता है, 'एन्यूमेरेबल। काउंटर ' विधि सामान्य है, फिर भी जांचता है कि टीएसओआर एक विशाल, विशाल प्रदर्शन लाभ प्राप्त करने के लिए आईसीओलेक्शन है या नहीं। पुनरावृत्ति के बजाय गणना करें। हां, एक बढ़त मामला और मैं मानता हूं कि यह कोड गंध नहीं है, लेकिन इसके लिए अच्छे कारण हो सकते हैं। –

+2

@ माइकलस्टम: मैं आपका अंक लेता हूं। हालांकि, यह अभी भी एक ऑब्जेक्ट * पूछने के लिए एक सुंदर "जेनेरिक" चीज है * क्या आप इस इंटरफ़ेस का समर्थन करते हैं? " गैर-जेनेरिक कोड उस तरह की चीज भी करता है। लेकिन जब आप कहते हैं, "यदि टी वास्तव में हैशटेबल प्रकार के रूप में हुआ ..." तो टी का सामान्य रूप से उपयोग नहीं किया जा रहा है। –

+0

आह, मुझे लगता है कि मैं देखता हूं। दार्शनिक रूप से, आप कहते हैं कि "मुझे परवाह है कि यह एक पद्धति को लागू करता है जो मुझे अपेक्षित व्यवहार के साथ गणना करता है जैसा कि आईसीओलेक्शन द्वारा परिभाषित किया गया है (उर्फ। यह ऐसी भयानक चीजें नहीं करनी चाहिए जिन्हें मैं लाउडस्पीकर के माध्यम से 1 से एक्स तक गिनने की अपेक्षा नहीं करता)" ? (बस इस चीज के पीछे डिजाइन दर्शन को समझने की कोशिश कर रहा है "यह चीजों को बहुत तेज करता है") –

संबंधित मुद्दे