प्रत्यक्ष कास्टिंग बनाम 'ऑपरेटर' के रूप में?


709

निम्नलिखित कोड पर विचार करें:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

तीन प्रकार की कास्टिंग के बीच क्या अंतर है (ठीक है, तीसरा एक कास्टिंग नहीं है, लेकिन आपको इरादा मिलता है)। कौन सा पसंद किया जाना चाहिए?


1
काफी डुप्लिकेट नहीं है, लेकिन पिछले प्रश्न में कुछ प्रदर्शन चर्चाएं भी हैं ।
बिना लाइसेंस के

8
4 string s = Convert.ToString(o):; 5 वां: string s = $"{o}"(या string.Formatपहले सी # के लिए फॉर्म के बराबर )
पृथ्वी इंजन

जवाबों:


833
string s = (string)o; // 1

यदि कोई नहीं है, तो InvalidCastException को फेंकता oहै string। अन्यथा, को असाइन करता oहै s, भले ही oहै null

string s = o as string; // 2

यदि नहीं है या यदि है तो असाइन nullकरता है । इस कारण से, आप इसे मान प्रकार के साथ उपयोग नहीं कर सकते हैं (ऑपरेटर उस स्थिति में वापस नहीं लौट सकता है )। अन्यथा, को सौंपता है ।sostringonullnullos

string s = o.ToString(); // 3

यदि कोई NullReferenceException कारण oहै null। जो कुछ भी o.ToString()लौटता है s, वह बताता है कि कोई भी प्रकार नहीं oहै।


अधिकांश रूपांतरणों के लिए 1 का उपयोग करें - यह सरल और सीधा है। मैं लगभग कभी भी 2 का उपयोग नहीं करता हूं क्योंकि अगर कुछ सही प्रकार नहीं है, तो मैं आमतौर पर अपवाद होने की उम्मीद करता हूं। मैंने केवल बुरी तरह से डिज़ाइन किए गए पुस्तकालयों के साथ इस रिटर्न-नल प्रकार की कार्यक्षमता की आवश्यकता देखी है जो त्रुटि कोड का उपयोग करते हैं (उदाहरण के लिए अपवाद का उपयोग करने के बजाय वापसी = त्रुटि)।

3 एक कास्ट नहीं है और सिर्फ एक विधि मंगलाचरण है। जब आप एक गैर-स्ट्रिंग ऑब्जेक्ट के स्ट्रिंग प्रतिनिधित्व की आवश्यकता के लिए इसका उपयोग करें।


2
जब आप स्पष्ट रूप से परिभाषित किए जाते हैं, तो आप 'null' को मान-प्रकारों में निर्दिष्ट कर सकते हैं, जैसे: int? मैं; स्ट्रिंग s = "5"; मैं = इंट के रूप में; // i अब 5 s = null है; मैं = इंट के रूप में; // i अब अशक्त है
Anheledir

3
पुन :: Anheledir वास्तव में मैं पहली कॉल के बाद अशक्त हो जाएगा। स्ट्रिंग का मान प्राप्त करने के लिए आपको एक स्पष्ट रूपांतरण फ़ंक्शन का उपयोग करना होगा।
ग्वेंटे सेप

45
रे: सैंडर वास्तव में उपयोग करने के लिए एक और बहुत अच्छा कारण है, यह आपके चेकिंग कोड को सरल करता है (चेक फ़ॉर नल (इसके बजाय नल और सही प्रकार के लिए जांच करें) यह तब से उपयोगी है जब आप एक कस्टम एक अपवाद को फेंक देंगे। लेकिन यह बहुत सच है कि कॉल के रूप में अंधा खराब है।
ग्वेंटे

5
# 2 समान तरीकों की चीजों के लिए आसान है, जहां आप इनपुट प्रकार को नहीं जानते हैं। हालांकि आमतौर पर, हां, 1 को प्राथमिकता दी जाएगी। हालांकि उस पर प्राथमिकता दी जाती है कि जाहिर तौर पर टाइप सिस्टम का उपयोग एक प्रकार तक सीमित करने के लिए किया जाएगा जब आप केवल एक ही उम्मीद करते हैं :)
Calum

6
# 2 तब भी उपयोगी होता है जब आपके पास एक विशिष्ट प्रकार के लिए कुछ विशिष्ट करने के लिए कोड हो, लेकिन अन्यथा कुछ भी नहीं करेगा।
एंथोनीवजोन

349
  1. string s = (string)o;उपयोग करें जब कुछ निश्चित रूप से दूसरी चीज होनी चाहिए ।
  2. string s = o as string;उपयोग करें जब कुछ दूसरी चीज हो सकती है।
  3. string s = o.ToString(); उपयोग करें जब आप परवाह नहीं करते हैं कि यह क्या है लेकिन आप उपलब्ध स्ट्रिंग प्रतिनिधित्व का उपयोग करना चाहते हैं।

1
मुझे लगता है कि यह उत्तर अच्छा लग रहा है, लेकिन यह सटीक नहीं हो सकता है।
j riv

1
मुझे पहले दो पसंद हैं, लेकिन मैं जोड़ूंगा "और आपको यकीन है कि यह शून्य नहीं है" तीसरे विकल्प के लिए।
२०:४२ पर Uxonith

2
आप इन दिनों एल्विस उपयोग कर सकते हैं कि के बारे में देखभाल करने के लिए होने से बचाने के (?।): obj .ToString ()
Quibblesome

@Quibblesome - शानदार जवाब लेकिन मुझे आपके रिबूट के बारे में सोचने के लिए रुकना पड़ा! यह सचमुच मेरे दिमाग को उड़ा देता है कि भाषा लगभग 15 वर्षों से अच्छी है। यह कल की तरह लगता है जब हम सभी "नुकीले" हो रहे थे ताकि वरिष्ठ देवों को C # स्विच करने के लिए मनाने की कोशिश की जा सके।
ग्रिस्वाल्ड_

1
@Quibblesome अच्छा जवाब: अगर आप 1/2/3 में जोड़ते हैं तो क्या आप नाराज हो जाएंगे ताकि ओपी तक स्क्रॉल करना जरूरी न हो। मैं एसओ के साथ वोटों के अनुसार पुराने उत्तर देगा!
Whytheq

29

यह वास्तव में इस बात पर निर्भर करता है कि क्या आप जानते हैं कि क्या oएक स्ट्रिंग है और आप इसके साथ क्या करना चाहते हैं। यदि आपकी टिप्पणी का अर्थ है कि oवास्तव में एक स्ट्रिंग है, तो मैं सीधे (string)oकलाकारों को पसंद करूंगा - यह विफल होने की संभावना नहीं है।

स्ट्रेट कास्ट का उपयोग करने का सबसे बड़ा फायदा यह है कि जब यह विफल होता है, तो आपको एक InvalidCastException मिलती है , जो आपको बताती है कि क्या गलत हुआ।

asऑपरेटर के साथ , यदि oकोई स्ट्रिंग नहीं है , तो उसे sसेट कर दिया जाता है null, जो यदि आप अनिश्चित हैं तो परीक्षण करना चाहते हैं s:

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

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

स्ट्रिंग में कनवर्ट करने के विशेष मामले में, प्रत्येक ऑब्जेक्ट में एक है ToString, इसलिए आपकी तीसरी विधि ठीक हो सकती है यदि oयह शून्य नहीं है और आपको लगता है कि ToStringविधि वह कर सकती है जो आप चाहते हैं।


2
एक नोट - आप अशक्त मूल्य प्रकारों के asसाथ उपयोग कर सकते हैं । IE काम नहीं करेगा, लेकिन ...o as DateTimeo as DateTime?
जॉन गिब्ब

if (s is string)इसके बजाय का उपयोग क्यों नहीं ?
बोर्नटोडकोड

1
@BornToCode, मेरे लिए, काफी हद तक व्यक्तिगत पसंद। आप जो कर रहे हैं उसके आधार पर, अक्सर isआईएनजी के बाद , आपको किसी भी तरह फिर से कास्ट करना होगा, इसलिए आपके पास एक हार्ड कास्ट है। किसी कारण से, asऔर अशक्त जांच मुझे बेहतर लगी।
ब्लेयर कॉनराड

9

यदि आप पहले से जानते हैं कि यह किस प्रकार का हो सकता है, तो सी-स्टाइल कास्ट का उपयोग करें:

var o = (string) iKnowThisIsAString; 

ध्यान दें कि केवल C- शैली के कलाकारों के साथ ही आप स्पष्ट प्रकार का प्रदर्शन कर सकते हैं।

यदि आपको नहीं पता कि यह वांछित प्रकार है और आप इसका उपयोग करने जा रहे हैं यदि यह है, तो कीवर्ड के रूप में उपयोग करें :

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

ध्यान दें कि किसी भी प्रकार के रूपांतरण ऑपरेटरों को कॉल नहीं किया जाएगा। यह केवल गैर-शून्य होगा यदि ऑब्जेक्ट शून्य और मूल रूप से निर्दिष्ट प्रकार का नहीं है।

किसी भी वस्तु का मानव-पठनीय स्ट्रिंग प्रतिनिधित्व प्राप्त करने के लिए ToString () का उपयोग करें, भले ही वह स्ट्रिंग के लिए डाली न जाए।


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

7

जब आप FindControl पद्धति का उपयोग करते हैं, तो asp.net में कीवर्ड अच्छा है।

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

इसका मतलब है कि आप टाइप किए गए वैरिएबल पर काम कर सकते हैं, फिर उसके बाद इसे objectऐसे डाल सकते हैं जैसे आप सीधे कलाकारों के साथ करेंगे:

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

यह बहुत बड़ी बात नहीं है, लेकिन यह कोड और चर असाइनमेंट की लाइनों को बचाता है, साथ ही यह अधिक पठनीय है


6

'as' पर आधारित है 'is', जो कि एक कीवर्ड है जो रनटाइम पर जांच करता है यदि ऑब्जेक्ट पॉलीमॉर्फिक रूप से संगत है (मूल रूप से एक कास्ट बनाया जा सकता है) और चेक विफल होने पर वापस आ जाता है।

ये दोनों बराबर हैं:

'As' का उपयोग करना:

string s = o as string;

'का उपयोग कर रहा है':

if(o is string) 
    s = o;
else
    s = null;

इसके विपरीत, सी-स्टाइल कास्ट रनटाइम पर भी बनाया जाता है, लेकिन एक अपवाद फेंकता है अगर कलाकारों को नहीं बनाया जा सकता है।

बस एक महत्वपूर्ण तथ्य जोड़ने के लिए:

'As' कीवर्ड केवल संदर्भ प्रकारों के साथ काम करता है। आप ऐसा नहीं कर सकते हैं:

// I swear i is an int
int number = i as int;

उन मामलों में आपको कास्टिंग का उपयोग करना होगा।


मेरी गलती को इंगित करने के लिए धन्यवाद, आप सही हैं। मैंने उत्तर संपादित किया। अरे! माफ़ करना।
सर्जियो अकोस्टा

5

2 व्युत्पन्न प्रकार के लिए कास्टिंग के लिए उपयोगी है।

मान लीजिए कि एक जानवर है:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

न्यूनतम जातियों के साथ एक तंग आ जाएगा ।


2
@ चेयर माउट्रे, यह हमेशा संभव नहीं है, खासकर अगर यह एक पुस्तकालय है।
deceleratedcaviar

5

इस पृष्ठ पर चलाए गए प्रयोगों के अनुसार: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(यह पृष्ठ कुछ "अवैध रेफ़रर" त्रुटियां दिखा रहा है, कभी-कभी ऐसा करते हैं तो बस ताज़ा करें)

निष्कर्ष है, "के रूप में" ऑपरेटर एक डाली की तुलना में सामान्य रूप से तेज है। कभी-कभी कई बार तेजी से, कभी-कभी तो बस तेजी से।

मैं हमेशा "के रूप में" भी अधिक पठनीय है।

इसलिए, चूंकि यह तेजी से और "सुरक्षित" (अभ्यस्त फेंक अपवाद) दोनों है, और संभवतः पढ़ने में आसान है, मैं हर समय "के रूप में" का उपयोग करने की सलाह देता हूं।


4

"(स्ट्रिंग) ओ" के रूप में कोई प्रत्यक्ष कलाकारों के रूप में एक InvalidCastException में परिणाम होगा।

"ओ स्ट्रिंग के रूप में" एक अपवाद होने के बजाय एक अशक्त संदर्भ होने के परिणामस्वरूप होगा।

"o.ToString ()" किसी भी प्रकार के कलाकारों की एक प्रति नहीं है, यह एक ऐसी विधि है जिसे ऑब्जेक्ट द्वारा कार्यान्वित किया जाता है, और इस तरह एक या दूसरे तरीके से, हर वर्ग में .net कि "कुछ करता है" के उदाहरण के साथ। वह कक्षा जिसे वह कहा जाता है और एक स्ट्रिंग लौटाता है।

यह मत भूलो कि स्ट्रिंग में बदलने के लिए, Convert.ToString (someType instOfThatType) भी है जहाँ someType एक प्रकार के सेट में से एक है, अनिवार्य रूप से फ्रेम बेस के प्रकार।


3

सभी दिए गए उत्तर अच्छे हैं, अगर मैं कुछ जोड़ सकता हूं: सीधे स्ट्रिंग के तरीकों और गुणों का उपयोग करने के लिए (जैसे ToLower) आप नहीं लिख सकते हैं:

(string)o.ToLower(); // won't compile

आप केवल लिख सकते हैं:

((string)o).ToLower();

लेकिन आप इसके बजाय लिख सकते हैं:

(o as string).ToLower();

asविकल्प (कम से कम मेरी राय के लिए) और अधिक पठनीय है।


(o स्ट्रिंग के रूप में) .Toower () निर्माण ऑपरेटर के उद्देश्य को हरा देता है। यह एक अशक्त संदर्भ अपवाद को फेंक देगा जब ओ को स्ट्रिंग में नहीं डाला जा सकता है।
जेम्स

@james - लेकिन किसने कहा कि ऑपरेटर के रूप में एकमात्र उद्देश्य कास्ट फेल होने पर अपवाद फेंकना है? यदि आप जानते हैं कि ओ एक स्ट्रिंग है और बस क्लीनर कोड लिखना चाहते हैं, तो आप (o as string).ToLower()कई भ्रामक कोष्ठक के बजाय उपयोग कर सकते हैं ।
बॉर्नटूकोड

जैसा कि इसका उद्देश्य काफी विपरीत है - यह अपवाद नहीं फेंकना चाहिए जब कलाकार विफल हो जाता है, तो उसे अशक्त होना चाहिए। मान लीजिए कि आपका ओ शून्य के मान के साथ एक स्ट्रिंग है, तब क्या होगा? संकेत - आपका ToLower कॉल विफल हो जाएगा।
जेम्स

@ जेम्स - आप सही कह रहे हैं, लेकिन उन मामलों के बारे में जहां मुझे पता है कि यह शून्य नहीं होगा और मुझे कंपाइलर के लिए कास्टिंग करने की जरूरत है ताकि मैं उस वस्तु के तरीकों का उपयोग कर सकूं?
बॉर्नटोड कोड

1
आप निश्चित रूप से ऐसा कर सकते हैं, लेकिन यह वास्तव में सबसे अच्छा अभ्यास नहीं है क्योंकि आप कॉलर या बाहरी सिस्टम पर भरोसा नहीं करना चाहते हैं ताकि यह सुनिश्चित हो सके कि आपका मूल्य शून्य नहीं है। यदि आप C # 6 का उपयोग कर रहे हैं, तो आप कर सकते हैं (ओ स्ट्रिंग के रूप में) ?. नीचा करना()।
जेम्स

3
string s = o as string; // 2

पसंद किया जाता है, क्योंकि यह डबल कास्टिंग के प्रदर्शन के दंड से बचा जाता है।


हाय क्रिस, इस जवाब में था कि लिंक अब एक 404 है ... मुझे यकीन नहीं है कि अगर आपको कोई प्रतिस्थापन मिला है तो आप इसे जगह में रखना चाहते हैं?
मैट

3

ऐसा लगता है कि उनमें से दोनों वैचारिक रूप से भिन्न हैं।

प्रत्यक्ष कास्टिंग

प्रकारों का कड़ाई से संबंधित होना आवश्यक नहीं है। यह सभी प्रकार के स्वादों में आता है।

  • कस्टम निहित / स्पष्ट कास्टिंग: आमतौर पर एक नई वस्तु बनाई जाती है।
  • मान प्रकार लागू करें : बिना जानकारी खोए कॉपी करें।
  • मान प्रकार स्पष्ट: प्रतिलिपि और जानकारी खो सकती है।
  • IS-A संबंध: संदर्भ प्रकार बदलें, अन्यथा अपवाद फेंकता है।
  • समान प्रकार: 'कास्टिंग निरर्थक है'।

ऐसा महसूस होता है कि वस्तु किसी और चीज में परिवर्तित होने जा रही है।

एएस ऑपरेटर

प्रकारों का सीधा संबंध है। जैसे की:

  • संदर्भ प्रकार: आईएस-ए संबंध वस्तुएं हमेशा समान होती हैं, बस संदर्भ बदल जाता है।
  • मूल्य प्रकार: कॉपी बॉक्सिंग और अशक्त प्रकार।

ऐसा महसूस होता है कि आप एक अलग तरीके से ऑब्जेक्ट को संभालने जा रहे हैं।

नमूने और आईएल

    class TypeA
    {
        public int value;
    }

    class TypeB
    {
        public int number;

        public static explicit operator TypeB(TypeA v)
        {
            return new TypeB() { number = v.value };
        }
    }

    class TypeC : TypeB { }
    interface IFoo { }
    class TypeD : TypeA, IFoo { }

    void Run()
    {
        TypeA customTypeA = new TypeD() { value = 10 };
        long longValue = long.MaxValue;
        int intValue = int.MaxValue;

        // Casting 
        TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL:  call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
        IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass  ConsoleApp1.Program/IFoo

        int loseValue = (int)longValue; // explicit -- IL: conv.i4
        long dontLose = intValue; // implict -- IL: conv.i8

        // AS 
        int? wraps = intValue as int?; // nullable wrapper -- IL:  call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
        object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
        TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
        IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo

        //TypeC d = customTypeA as TypeC; // wouldn't compile
    }

2

मैं के निम्नलिखित विशेष ओर ध्यान आकर्षित करना चाहते हैं के रूप में ऑपरेटर:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

ध्यान दें कि जैसा कि ऑपरेटर केवल संदर्भ रूपांतरण, अशक्त रूपांतरण और बॉक्सिंग रूपांतरण करता है। ऑपरेटर अन्य रूपांतरणों जैसे उपयोगकर्ता-परिभाषित रूपांतरणों का प्रदर्शन नहीं कर सकता है, जो कि कास्ट एक्सप्रेशंस का उपयोग करके किया जाना चाहिए।


0

किसी भी (किसी भी प्रकार का) का स्ट्रिंग प्रतिनिधित्व प्राप्त करने की कोशिश करते समय, जो संभावित रूप से अशक्त हो सकता है, मैं कोड की निचली पंक्ति को पसंद करता हूं। यह कॉम्पैक्ट है, यह ToString () को आमंत्रित करता है, और यह सही ढंग से नल को संभालता है। यदि o अशक्त है, तो String.Empty सम्‍मिलित होगा।

String s = String.Concat(o);

0

चूँकि किसी ने इसका उल्लेख नहीं किया था, उदाहरण के लिए जावा के लिए सबसे नजदीकी यह है:

obj.GetType().IsInstanceOfType(otherObj)

0

डायरेक्ट कास्ट का उपयोग करें string s = (string) o;यदि आपके ऐप stringका तार्किक संदर्भ एकमात्र मान्य प्रकार है। इस दृष्टिकोण के साथ, आप फेल-फास्टInvalidCastException के सिद्धांत को प्राप्त करेंगे और लागू करेंगे । आपके तर्क को अमान्य प्रकार को आगे पास करने से सुरक्षित किया जाएगा या यदि ऑपरेटर का उपयोग किया जाता है तो NullReferenceException प्राप्त करें ।as

यदि तर्क कई अलग-अलग प्रकारों की अपेक्षा करता है string s = o as string;और इसे ऑपरेटर पर nullया उपयोग isकरता है।

कास्ट को आसान बनाने के लिए C # 7.0 में नया शांत फीचर दिखाई दिया है और एक पैटर्न मिलान है :

if(o is string s)
{
  // Use string variable s
}

or

switch (o)
{
  case int i:
     // Use int variable i
     break;
  case string s:
     // Use string variable s
     break;
 }

0

निम्न प्रकार के रूपांतरण के दो प्रकार (कास्टिंग) C # में समर्थित हैं:

|

(सीवी

• दिए गए अभिव्यक्ति में v के स्थिर प्रकार को c में परिवर्तित करें

• केवल तभी संभव है जब v का गतिशील प्रकार c, या c का उप-प्रकार है

यदि नहीं, तो एक InvalidCastException को फेंक दिया जाता है

|

v सी के रूप में

• (सी) वी के गैर-घातक संस्करण

• इस प्रकार, दिए गए अभिव्यक्ति में स्थिर प्रकार v को c में परिवर्तित करें

• यदि v का गतिशील प्रकार c नहीं है, या c का उप-प्रकार है, तो अशक्त हो जाता है

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