2011-11-17 23 views
58

मैं Get<int>(Stat); या Get<string>(Name);परोक्ष 'टी'

लेकिन जब संकलन मैं कॉल कर सकते हैं करने के लिए कनवर्ट नहीं कर सकता प्रकार 'इंट':

परोक्ष 'टी'

के प्रकार 'int' कनवर्ट नहीं कर सकता

और string के लिए एक ही चीज़।

public T Get<T>(Stats type) where T : IConvertible 
{ 
    if (typeof(T) == typeof(int)) 
    { 
     int t = Convert.ToInt16(PlayerStats[type]); 
     return t; 
    } 
    if (typeof(T) == typeof(string)) 
    { 
     string t = PlayerStats[type].ToString(); 
     return t; 
    } 
} 
+4

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

उत्तर

99

किसी भी समय जब आप खुद को एक सामान्य में किसी प्रकार पर स्विच करते हैं तो आप निश्चित रूप से कुछ गलत कर रहे हैं। जेनेरिक जेनेरिक होना चाहिए; उन्हें प्रकार से पूरी तरह से स्वतंत्र रूप से संचालित करना चाहिए।

यदि टी केवल int या स्ट्रिंग हो सकता है तो पहले अपना कोड इस तरह से बिल्कुल न लिखें। दो विधियों को लिखें, जो एक int और एक स्ट्रिंग देता है जो एक देता है।

+2

क्या आप गलत हो जाएंगे जब आप गलत होंगे? –

+1

प्राप्त करें जहां कार आईकोनवर्टिबल लागू करता है तो टूट जाएगा। जब कोई देखता है कि आपके पास एक सामान्य विधि है तो वे मान लेंगे कि वे आईकोनवर्टिबल लागू करने वाली किसी भी चीज में गुजर सकते हैं। – Tjaart

+5

मैं केवल आपके साथ आंशिक रूप से सहमत हूं, @Eric। मुझे ऐसी स्थिति है जहां मुझे XML-टैग में संग्रहीत सरणी को पार्स करना होगा। समस्या यह है कि एक्सएमएल दस्तावेज़ निम्नानुसार है (मेरे मामले में COLLADA) का कहना है कि ऐसे सरणी न केवल फ्लोट, इंट और बूल बल्कि कुछ कस्टम प्रकार भी हों। हालांकि यदि आपको फ्लोट मिलता है [] (सरणी टैग में उनके नामों में संग्रहीत डेटा का प्रकार होता है: float_array स्टोर्स फ्लोट्स) आपको स्ट्रिंग को सरणी के रूप में पार्स करने की आवश्यकता होती है फ्लोट्स के लिए, जिन्हें कुछ IFormatProvider का उपयोग करने की आवश्यकता होती है)। मैं स्पष्ट रूप से "टी। पर्स (...)" का उपयोग नहीं कर सकता। इसलिए मामलों के एक छोटे से सबसेट के लिए मुझे इस तरह के स्विचिंग का उपयोग करने की आवश्यकता है। – rbaleksandar

9
public T Get<T>(Stats type) where T : IConvertible 
{ 
    if (typeof(T) == typeof(int)) 
    { 
     int t = Convert.ToInt16(PlayerStats[type]); 
     return t as T; 
    } 
    if (typeof(T) == typeof(string)) 
    { 
     string t = PlayerStats[type].ToString(); 
     return t as T; 
    } 
} 
+2

'वापसी (टी) टी; 'क्योंकि कोई शून्य जांच आवश्यक नहीं है। – BoltClock

+1

अगर स्थिति कोई शून्य –

+0

हा जांचें! +1: मेरे पास एक अलग मुद्दा था लेकिन टी के रूप में वापसी टी ने इसे मेरे लिए हल किया। धन्यवाद। – CodeChops

95

तुम सिर्फ अपने कस्टम कोड के बजाय Convert.ChangeType() उपयोग करने के लिए सक्षम होना चाहिए:

public T Get<T>(Stats type) where T : IConvertible 
{ 
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T)); 
} 
+2

धन्यवाद जो पूरी तरह से काम करता है –

+7

'वापसी (टी) (ऑब्जेक्ट) प्लेयरस्टैट्स [प्रकार] के बारे में कैसे;' – maxp

+0

उत्तर देने के लिए धन्यवाद। नेवर से नेवर"। – mikesigs

3

ऐसा लगता है कि आप एक TypeConverter की जरूरत है, this blog entry देखते हैं।

6

ChangeType शायद आपका सबसे अच्छा विकल्प है। मेरा समाधान ब्रोकनग्लस द्वारा प्रदान किए गए एक के समान है, जिसमें थोड़ा सा प्रयास तर्क है।

static void Main(string[] args) 
{ 
    object number = "1"; 
    bool hasConverted; 
    var convertedValue = DoConvert<int>(number, out hasConverted); 

    Console.WriteLine(hasConverted); 
    Console.WriteLine(convertedValue); 
} 

public static TConvertType DoConvert<TConvertType>(object convertValue, out bool hasConverted) 
{ 
    hasConverted = false; 
    var converted = default(TConvertType); 
    try 
    { 
     converted = (TConvertType) 
      Convert.ChangeType(convertValue, typeof(TConvertType)); 
     hasConverted = true; 
    } 
    catch (InvalidCastException) 
    { 
    } 
    catch (ArgumentNullException) 
    { 
    } 
    catch (FormatException) 
    { 
    } 
    catch (OverflowException) 
    { 
    } 

    return converted; 
} 
4

@BrokenGlass तर्क (Convert.ChangeType) को ध्यान में रखते GUID प्रकार के लिए समर्थन नहीं करता।

public T Get<T>(Stats type) where T : IConvertible 
{ 
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T)); 
} 

त्रुटि: 'System.Guid' को 'System.String' से अमान्य कलाकार।

इसके बजाय, System.ComponentModel नामस्थान जोड़ कर TypeDescriptor.GetConverter का उपयोग करके नीचे तर्क का उपयोग करें।

public T Get<T>(Stats type) where T : IConvertible 
{ 
    (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type]) 
} 

this पढ़ें।

5

इस प्रयास करें:

public T Get<T>(Stats type) where T : IConvertible 
{ 
    if (typeof(T) == typeof(int)) 
    { 
     return (T)(object)Convert.ToInt16(PlayerStats[type]); 

    } 
    if (typeof(T) == typeof(string)) 
    { 

     return (T)(object)PlayerStats[type]; 
    } 
} 
+0

धन्यवाद यह आपकी मदद करता है, मेरी ज़रूरत अलग है। मैं एक मौजूदा स्थैतिक विधि के लिए एक नकली विधि लिख रहा हूं ताकि मैं इसका परीक्षण कर सकूं। इस http://osherove.com/blog/2012/7/8/faking-static-methods-in-moq-fakeiteasy-and-nsubstitute-migh.html का उपयोग करना – Esen

0

असल में, आप बस इसे object को T में बदल सकते हैं और उसके बाद।

T var = (T)(object)42;

एक उदाहरण bool के लिए:

public class Program 
{ 
    public static T Foo<T>() 
    { 
     if(typeof(T) == typeof(bool)) { 
      return (T)(object)true; 
     } 

     return default(T); 
    } 

    public static void Main() 
    { 
     bool boolValue = Foo<bool>(); // == true 
     string stringValue = Foo<string>(); // == null 
    } 
} 

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

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