'T' प्रकार के मान को परिवर्तित नहीं किया जा सकता है


146

यह संभावना नौसिखिया सवाल है, लेकिन Google ने आश्चर्यजनक रूप से एक उत्तर नहीं दिया।

मेरे पास यह कृत्रिम विधि है

T HowToCast<T>(T t)
{
    if (typeof(T) == typeof(string))
    {
        T newT1 = "some text";
        T newT2 = (string)t;
    }

    return t;
}

C ++ बैकग्राउंड से आने से मुझे उम्मीद है कि यह काम करेगा। हालांकि, यह उपरोक्त दोनों असाइनमेंट के लिए "टी 'को स्ट्रिंग में परिवर्तित नहीं कर सकता है और" टाइप' को 'टाइप' में नहीं बदल सकता है।

मैं या तो वैचारिक रूप से कुछ गलत कर रहा हूं या सिर्फ गलत सिंटेक्स है। कृपया मुझे इस एक को सुलझाने में मदद करें।

धन्यवाद!


20
IMO, यदि आप अपने जेनरिक कोड में प्रकारों की जाँच कर रहे हैं, तो शायद जेनरिक आपकी समस्या का सही समाधान नहीं हैं।
ऑस्टिन सलोनन

अभिव्यक्ति typeof(T) == typeof(string)को रनटाइम पर हल किया जाता है, संकलन-समय पर नहीं। इस प्रकार ब्लॉक में निम्नलिखित लाइन अमान्य है।
स्टीव गाइडी

8
(टी) Convert.ChangeType (newT1, टाइपोफ़ (T))
विस्मयादिबोध

2
@vsapiha, केवल तभी काम करता है जब ऑब्जेक्ट IConvertible को लागू करता है। मिठास अगर यह हालांकि करता है।
ouflak

जवाबों:


285

भले ही यह एक ifब्लॉक के अंदर हो , लेकिन कंपाइलर को यह पता नहीं होता Tहै string
इसलिए, यह आपको कास्ट नहीं करने देता। (इसी कारण है कि आप डाली नहीं कर सकते DateTimeकरने के लिए string)

आपको object(जिसे कोई भी Tडाल सकता है), और वहाँ से string(जब से objectडाली जा सकती है string) को कास्ट करने की आवश्यकता है ।
उदाहरण के लिए:

T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;

2
यह काम! मैं अनुमान लगा रहा हूं कि दूसरा भी T newT2 = (T) (ऑब्जेक्ट) t होना चाहिए; हालांकि यह एक सेशन नहीं है।
एलेक्स

2
जोड़: C ++ टेम्पलेट अनिवार्य रूप से सही मानों के साथ संकलित समय पर कट-एंड-पेस्ट हैं। C # में वास्तविक जेनेरिक टेम्प्लेट (इसका एक "तात्कालिकता नहीं) संकलन के बाद मौजूद है और इस प्रकार निर्दिष्ट प्रकार की सीमा के पार सामान्य होना चाहिए।

(स्ट्रिंग) (वस्तु) टी; यहाँ कुछ भी नहीं है, लेकिन साथ ही साथ बाहर छोड़ सकता है, (स्ट्रिंग) (वस्तु) जो है
डॉग्जैट

6
सिर्फ "स्ट्रिंग के रूप में" का उपयोग क्यों नहीं किया जाता है? उदाहरण के लिए, यह ठीक संकलित करता है (मैं सचमुच त्रुटियों के बिना इसे संकलित करता हूं) जब userDefinedValue प्रकार का होता है T:var isBlank = (userDefinedValue is string) && String.IsNullOrWhiteSpace(userDefinedValue as string);
Triynko

1
ऐसा लगता है कि संकलक डिजाइनरों द्वारा एक गलती है। यदि सभी टी को विस्फोटक रूप से ऑब्जेक्ट में डाला जा सकता है और सभी ऑब्जेक्ट को आसानी से स्ट्रिंग में डाला जा सकता है, तो एक संक्रामक नियम मौजूद होना चाहिए कि टी स्पष्ट रूप से स्ट्रिंग में डाला जा सकता है। यदि आप गलत तरीके से कलाकारों का प्रदर्शन करते हैं तो एक रनटाइम त्रुटि होनी चाहिए।
पी। ब्रायन। मैके

10

दोनों लाइनों में एक ही समस्या है

T newT1 = "some text";
T newT2 = (string)t;

संकलक को पता नहीं है कि टी एक स्ट्रिंग है और इसलिए यह जानने का कोई तरीका नहीं है कि कैसे असाइन किया जाए। लेकिन जब से आप की जाँच की आप बस के साथ इसे मजबूर कर सकते हैं

T newT1 = "some text" as T;
T newT2 = t; 

आपको टी कास्ट करने की आवश्यकता नहीं है क्योंकि यह पहले से ही एक स्ट्रिंग है, बाधा को भी जोड़ने की आवश्यकता है

where T : class

2
गलत। यह संकलन नहीं होगा। मेरा जवाब देखिए।
एसएलके

2
संकलन बस ठीक है (जहां है, जहां मैंने पोस्ट करने के कुछ सेकंड बाद जोड़ा, शायद वह छूट गया हो)। उफ़ एनएम कलाकारों को बदलने के लिए भूल गया
डोगेट

2

मुझे समान कोड पता है कि ओपी ने जेनेरिक पार्सर्स से इस सवाल में पोस्ट किया। एक प्रदर्शन के नजरिए से, आपको उपयोग करना चाहिए Unsafe.As<TFrom, TResult>(ref TFrom source), जो System.Runtime.CompilerServices.Unsafe NuGang पैकेज में पाया जा सकता है । यह इन परिदृश्यों में मूल्य प्रकारों के लिए मुक्केबाजी से बचा जाता है। मुझे यह भी लगता है कि Unsafe.AsJIT द्वारा दो बार (उपयोग करके (TResult) (object) actualString) कास्टिंग की तुलना में कम मशीन कोड में परिणाम आया है , लेकिन मैंने इसकी जाँच नहीं की है।

public TResult ParseSomething<TResult>(ParseContext context)
{
    if (typeof(TResult) == typeof(string))
    {
        var token = context.ParseNextToken();
        string parsedString = token.ParseToDotnetString();
        return Unsafe.As<string, TResult>(ref parsedString);
    }
    else if (typeof(TResult) == typeof(int))
    {
        var token = context.ParseNextToken();
        int parsedInt32 = token.ParseToDotnetInt32();
        // This will not box which might be critical to performance
        return Unsafe.As<int, TResult>(ref parsedInt32); 
    }
    // other cases omitted for brevity's sake
}

Unsafe.As जेआईटी द्वारा कुशल मशीन कोड निर्देशों के साथ प्रतिस्थापित किया जाएगा, जैसा कि आप आधिकारिक CoreFX रेपो में देख सकते हैं:

स्रोत कोड का Unsafe.As


1

यदि आप स्पष्ट प्रकारों की जाँच कर रहे हैं, तो आप उन चरों को क्यों घोषित कर रहे हैं T?

T HowToCast<T>(T t)
{
    if (typeof(T) == typeof(string))
    {
        var newT1 = "some text";
        var newT2 = t;  //this builds but I'm not sure what it does under the hood.
        var newT3 = t.ToString();  //for sure the string you want.
    }

    return t;
}

6
दूसरी पंक्ति प्रकार का एक चर बनाती है T
SL28s

आप पूछते हैं कि प्रकार की जांच क्यों करें? मान लें कि आपके पास एक आधार फ़ील्ड प्रकार है जो objectमूल्यों को संग्रहीत करता है, व्युत्पन्न प्रकारों के साथ जो मूल्यों को संग्रहीत stringकरता है। मान लें कि इन क्षेत्रों में "DefaultIfNotProvided" मान भी है, इसलिए आपको यह जांचने की आवश्यकता है कि क्या उपयोगकर्ता द्वारा प्रदान किया गया मूल्य (जो एक वस्तु या एक स्ट्रिंग या एक संख्यात्मक आदिम भी हो सकता है) के बराबर है default(T)। स्ट्रिंग को एक विशेष मामले के रूप में माना जा सकता है जहां एक खाली / व्हाट्सएप स्ट्रिंग को डिफ़ॉल्ट (टी) के समान माना जाता है, इसलिए आप जांचना चाहते हैं कि क्या हो सकता है T userValue; var isBlank = (userValue is string) && String.IsNullOrWhitespace(userValue as string);
त्रिकोको

0

यदि आपको अपनी कक्षा और विधि दोनों के लिए सामान्य घोषणा करनी है, तो आपको यह त्रुटि भी मिलेगी। उदाहरण के लिए नीचे दिखाया गया कोड यह संकलन त्रुटि देता है।

public class Foo <T> {

    T var;

    public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
        this.var = cls.newInstance();
    }

}

यह कोड संकलित करता है (विधि घोषणा से हटाया गया टी नोट):

public class Foo <T> {

    T var;

    public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
        this.var = cls.newInstance();
    }

}

-5

इस पंक्ति को बदलें:

if (typeof(T) == typeof(string))

इस लाइन के लिए:

if (t.GetType() == typeof(string))

1
वे एक ही हैं
bigworld12

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