'टी' के प्रकार को 'में' रूपांतरित नहीं किया जा सकता


90

मैं फोन कर सकता हूं 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;
    }
}

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

जवाबों:


132

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

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


1
<कार> प्राप्त करें जहां कार इम्प्लांट्स को लागू करती है, जिसके कारण टूटना होगा। जब कोई देखता है कि आपके पास एक सामान्य विधि है, तो वे मान लेंगे कि वे किसी भी चीज़ में गुजर सकते हैं जो कि IConvertible को लागू करता है।
तजार्ट

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

1
यह उत्तर आपको खरगोश के छेद से बाहर रखेगा। मैं एक कार्य को सामान्य बनाना चाहता था int, int?, bool, bool?, string, और यह असंभव प्रतीत होता था।
जेस

यह एक सामान्य प्रगणित प्रकार पर स्विच को व्यावहारिक बनाता है।
डेविड ए। ग्रे

1
मैं इसका उपयोग उत्तर के रूप में नहीं करना चाहता था। लेकिन वह सही है। मैं प्रकार की जांच करना चाहता था और, यदि कोई विशिष्ट है, तो उस पर एक संपत्ति निर्धारित करें। समाधान एक ऐसी विधि बनाना था जो एक दृढ़ता से टाइप किया हुआ पैरामीटर लेता था।
मैट डावी

139

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

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

20
कैसे के बारे मेंreturn (T)(object)PlayerStats[type];
अधिकतम

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

2
return (T) t;क्योंकि कोई शून्य जाँच आवश्यक नहीं है।
बोल्टलॉक

यह ऊपर मेरे लिए संकलन नहीं होगा। संकलन करने के लिए T को "जैसा" के लिए एक संदर्भ प्रकार होना चाहिए।
रॉबर्ट श्मिट

9

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;
}

मेरा उपयोग मामला एक सामान्य अमूर्त वर्ग से प्राप्त एक ठोस वर्ग है। वर्ग को सार के रूप में चिह्नित किया जाता है क्योंकि यह एक सार पद्धति को परिभाषित करता है जो आधार वर्ग के सामान्य निजी सदस्य पर संचालित होता है। जेनेरिक अपने सामान्य प्रकार पर C # 7.3 Enum बाधा का उपयोग करता है। मैंने अभी हाल ही में एक परीक्षण पूरा किया है, और यह ठीक वैसे ही काम करता है जैसा कि मुझे उम्मीद थी कि यह होगा।
डेविड ए। ग्रे

8

इसे इस्तेमाल करे:

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];
    }
}

धन्यवाद इस मदद की, मेरी जरूरत अलग है। मैं मौजूदा स्थैतिक विधि के लिए एक नकली विधि लिख रहा हूं ताकि मैं इसका परीक्षण कर सकूं। इस osherove.com/blog/2012/7/8/…
Esen

8

दरअसल, आप इसे सिर्फ 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टाइप के आधार पर कुछ अलग फंक्शनलिटीज जोड़ना चाहते हों ।


6

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

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

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

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

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

पढ़ें यह



0

आप बस नीचे की तरह डाल सकते हैं,

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