टी के लिए कास्ट ऑब्जेक्ट


90

मैं XmlReader.NET में कक्षा के साथ एक XML फ़ाइल पार्स कर रहा हूं और मैंने सोचा कि यह एक जेनेरिक पार्स फ़ंक्शन लिखने के लिए अलग-अलग विशेषताओं को पढ़ने के लिए स्मार्ट होगा। मैं निम्नलिखित समारोह के साथ आया:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}

जैसा कि मुझे एहसास हुआ, यह पूरी तरह से काम नहीं करता है जैसा कि मैंने योजना बनाई है; यह इस तरह के रूप आदिम प्रकार के साथ एक त्रुटि फेंकता है intया double, के बाद से एक डाली एक से परिवर्तित नहीं कर सकते stringएक अंकीय प्रकार के। क्या मेरे कार्य को संशोधित रूप में प्रस्तुत करने का कोई तरीका है?

जवाबों:


206

पहले यह देखने के लिए जांचें कि क्या यह डाली जा सकती है।

if (readData is T) {
    return (T)readData;
} 
try {
   return (T)Convert.ChangeType(readData, typeof(T));
} 
catch (InvalidCastException) {
   return default(T);
}

1
मैंने Convert.ChangeType: 'return (T) Convert.ChangeType (readData, typeof (T), System.Globalization.CultureInfo.InstalledUICulture .NumberFormat) के साथ लाइन बदलकर इसे विभिन्न विभिन्न सांस्कृतिक कॉन्फ़िगरेशन पर काम करने के लिए बनाया है।
कास्पर होल्डम

2
यह सही जवाब है। लेकिन मैं एक तर्क दे सकता हूं कि कोशिश / पकड़ यहां पूरी तरह से बेमानी है। विशेष रूप से मौन अपवाद को देखते हुए। मुझे लगता है कि अगर (रीडडाटा टी है) {...} भाग एक पर्याप्त प्रयास है।
pimbrouwers

यदि आप इसे परिवर्तित करने से पहले readDate शून्य है, तो आप देख सकते हैं। यदि ऐसा है तो डिफ़ॉल्ट (T) वापस करें।
मैनुएल कोच

मुझे लगता है कि "वस्तु को IConvertible को लागू करना चाहिए।"
केसी क्रुकस्टन

19

क्या आपने Convert.ChangeType की कोशिश की है ?

यदि विधि हमेशा एक स्ट्रिंग लौटाती है, जो मुझे अजीब लगती है, लेकिन यह इस बिंदु के अलावा है, तो शायद यह परिवर्तित कोड वही करेगा जो आप चाहते हैं:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)Convert.ChangeType(readData, typeof(T));
}

मैंने शुरू में Convert.ChangeType पर एक नज़र डाली थी, लेकिन यह तय किया कि यह इस ऑपरेशन के लिए उपयोगी नहीं था। आप और बॉब दोनों ने एक ही उत्तर दिया, और मैंने आपके उत्तरों के बीच एक मिश्रण के साथ जाने का फैसला किया, इसलिए मैंने कोशिश बयानों का उपयोग करने से परहेज किया, लेकिन जब भी संभव हो तब 'वापसी (टी) रीडडाटा का उपयोग किया।
कैस्पर होल्डम


3

आपको संदर्भ प्रकार के प्रकार की आवश्यकता हो सकती है:

 private static T ReadData<T>(XmlReader reader, string value) where T : class
 {
     reader.MoveToAttribute(value);
     object readData = reader.ReadContentAsObject();
     return (T)readData;
 }

और फिर एक और करें जो मान प्रकार और TryParse का उपयोग करता है ...

 private static T ReadDataV<T>(XmlReader reader, string value) where T : struct
 {
     reader.MoveToAttribute(value);
     object readData = reader.ReadContentAsObject();
     int outInt;
     if(int.TryParse(readData, out outInt))
        return outInt
     //...
 }

3

दरअसल, यहाँ समस्या ReadContentAsObject का उपयोग है। दुर्भाग्य से, यह विधि अपनी उम्मीदों पर खरा नहीं उतरती है; हालांकि इसे मूल्य के लिए सबसे उपयुक्त प्रकार का पता लगाना चाहिए, यह वास्तव में एक स्ट्रिंग लौटाता है, कोई फर्क नहीं पड़ता कि क्या (यह परावर्तक का उपयोग करके सत्यापित किया जा सकता है)।

हालाँकि, आपके विशिष्ट मामले में, आप पहले से ही जानते हैं कि आप किस प्रकार कास्ट करना चाहते हैं, इसलिए मैं कहूंगा कि आप गलत तरीके का उपयोग कर रहे हैं।

इसके बजाय ReadContentAs का उपयोग करने का प्रयास करें, यह वही है जो आपको चाहिए।

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAs(typeof(T), null);
    return (T)readData;
}

काफी कॉम्पैक्ट और एलिगेंट लगती हैं। हालाँकि, स्वीकृत उत्तर में समाधान ChangeType का उपयोग करता है जो कि एक IFormatProvider स्वीकार करने के बाद से कई अलग-अलग संस्कृतियों के साथ संगत है। चूँकि यह उस समाधान के लिए रखे जाने वाले प्रोजेक्ट के लिए एक उपयुक्तता है।
कास्पर होल्डम

2

आप संभवतः एक पैरामीटर के रूप में पास-इन कर सकते हैं, एक प्रतिनिधि जो स्ट्रिंग से टी में परिवर्तित हो जाएगा।


1

एक 'वर्ग' बाधा (या अधिक विस्तृत, एक बेस क्लास या आपके एक्सपेक्टेड टी ऑब्जेक्ट्स के इंटरफ़ेस की तरह) जोड़ें:

private static T ReadData<T>(XmlReader reader, string value) where T : class
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}

या where T : IMyInterfaceया where T : new(), आदि


1

दरअसल, प्रतिक्रियाएं एक दिलचस्प सवाल पेश करती हैं, जो कि आप चाहते हैं कि आपका कार्य त्रुटि के मामले में करना चाहिए।

शायद यह एक TryParse विधि के रूप में इसका निर्माण करने के लिए और अधिक समझ में आता है जो टी में पढ़ने का प्रयास करता है, लेकिन अगर यह नहीं किया जा सकता है तो वह गलत हो जाता है?

    private static bool ReadData<T>(XmlReader reader, string value, out T data)
    {
        bool result = false;
        try
        {
            reader.MoveToAttribute(value);
            object readData = reader.ReadContentAsObject();
            data = readData as T;
            if (data == null)
            {
                // see if we can convert to the requested type
                data = (T)Convert.ChangeType(readData, typeof(T));
            }
            result = (data != null);
        }
        catch (InvalidCastException) { }
        catch (Exception ex)
        {
            // add in any other exception handling here, invalid xml or whatnot
        }
        // make sure data is set to a default value
        data = (result) ? data : default(T);
        return result;
    }

संपादित करें: अब जब मैं इसके बारे में सोचता हूं, तो क्या मुझे वास्तव में Convert.changetype परीक्षण करने की आवश्यकता है? क्या रेखा पहले से ही ऐसा करने की कोशिश नहीं करती है? मुझे यकीन नहीं है कि अतिरिक्त चेंजगाइप कॉल करना वास्तव में कुछ भी पूरा करता है। वास्तव में, यह केवल अपवाद उत्पन्न करके प्रसंस्करण ओवरहेड को बढ़ा सकता है। अगर किसी को एक अंतर पता है जो इसे करने लायक बनाता है, तो कृपया पोस्ट करें!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.