2009-06-05 13 views
8

मुझे इस कीवर्ड का कार्य पता है, लेकिन मैं जानना चाहता हूं कि यह निम्न स्तर पर कैसे काम करता है।"as" कीवर्ड आंतरिक रूप से कैसे काम करता है?

कौन सा तेज़ है? और क्या वे हमेशा एक ही परिणाम देते हैं? यदि वे करते हैं, तो दो अलग-अलग तरीके क्यों हैं?

// Is there an overhead? An internal try catch? 
Class123 obj = someobject as Class123; 

if (Class123 != null) 
{ 
    //OK 
} 

या

Class123 obj = null; 

if (someobject is Class123) 
{ 
    obj = (Class123)someobject; 
} 
+1

उत्तर देख रहे हैं मुझे लगता है कि "है" सिर्फ यह जानना है कि कुछ वस्तु एक प्रकार है, और वे कुछ क्रियाएं करते हैं, न सिर्फ एक कलाकार। उदाहरण: यदि (ओबीजे क्लासमेनगर है) {लिखें ("आप एक प्रबंधक हैं")} –

उत्तर

16

कोई आंतरिक कोशिश पकड़ जब as कीवर्ड का उपयोग हो रहा है। कार्यक्षमता को कंपाइलर/सीएलआर में बनाया गया है, जहां तक ​​मुझे पता है, इसलिए टाइप चेक निहित और स्वचालित है।

सरल नियम:
जब आप हमेशा वस्तु एक ज्ञात प्रकार है (और इस प्रकार अगर यह गलत प्रकार का संयोग से है एक उपयोगी त्रुटि प्राप्त) करने की उम्मीद एक सीधा कलाकारों का प्रयोग करें। as कीवर्ड का उपयोग करें जब ऑब्जेक्ट हमेशा ज्ञात प्रकार का होता है।

as कीवर्ड के अस्तित्व का कारण पूरी तरह से प्रोग्रामर की सुविधा के लिए है (हालांकि आप यह सुझाव देने में सही हैं कि एक प्रयास-पकड़ धीमा हो जाएगा)। तुम खुद इस तरह के रूप मैन्युअल लागू कर सकता है, जैसा कि आप का कहना है:

var castObj = (obj is NewType) ? (NewType)obj : null; 

इस तथ्य पर प्रकाश डाला गया है कि 'के रूप में' कीवर्ड संक्षिप्तता के प्रयोजन के लिए मुख्य रूप से है।

अब, दोनों के बीच प्रदर्शन अंतर नगण्य होने की संभावना है। प्रकार की जांच के कारण as कीवर्ड शायद मामूली धीमा है, लेकिन यह अधिकांश स्थितियों में कोड को प्रभावित करने की संभावना नहीं है। जैसा कि कहा गया है, समयपूर्व अनुकूलन कभी करने के लिए एक बुद्धिमान बात नहीं है। यदि आप वास्तव में चाहते हैं तो बेंचमार्क, लेकिन मैं सलाह देता हूं कि जो भी तरीका आपकी स्थिति के लिए अधिक सुविधाजनक/अपरिवर्तनीय है, और प्रदर्शन के बारे में चिंता न करें (या बाद में यदि आपको बिल्कुल जरूरी है)।

+0

मैंने नल को नहीं सोचा था, जो महत्वपूर्ण है, लेकिन जब मैं "कोशिश" के बारे में कहता हूं, अगर ऑब्जेक्ट परिवर्तनीय नहीं था (क्षमा करें खराब अंग्रेजी के लिए) –

+4

निश्चित रूप से "जैसा" और एक कलाकार एक शून्य की उपस्थिति में समान व्यवहार करता है? क्या यह "प्रत्यक्ष कलाकार का उपयोग नहीं करना चाहिए जब आप किसी भी अन्य प्रकार के ऑब्जेक्ट की अपेक्षा कभी नहीं करते हैं, 'जब' ऑब्जेक्ट संभवतः किसी अन्य प्रकार का हो सकता है 'का उपयोग करें? – Grokys

+1

जैसा कि थोड़ा धीमा हो सकता है लेकिन यदि (x टी है) (टी) x.Foo() टाइपशेक को दो बार जरूरी है, शायद x == nul से थोड़ा धीमा। –

5

तेजी से हो सकता है क्योंकि केवल एक बार टाइप को फिर से जांचने की आवश्यकता होती है, जबकि + को दो बार टाइप करने की आवश्यकता होती है।

+0

मुझे यकीन नहीं है कि यह सही है। "जैसा" कीवर्ड बिल्कुल वही काम करता है, केवल स्पष्ट रूप से, जहां तक ​​मुझे पता है। – Noldorin

+0

यह व्याख्या FxCop में प्रदर्शन नियम के रूप में भी दी गई है। तो मुझे लगता है कि यह सही है। – Scoregraphic

22

MSDN: as (C# Reference) के अनुसार:

ऑपरेटर एक डाली आपरेशन की तरह है के रूप में। हालांकि, यदि रूपांतरण संभव नहीं है, तो अपवाद बढ़ाने के बजाय रिटर्न शून्य के रूप में। निम्नलिखित अभिव्यक्ति पर विचार करें:

expression as type 

यह निम्न अभिव्यक्ति के बराबर सिवाय इसके कि अभिव्यक्ति केवल एक बार मूल्यांकन किया जाता है है।

expression is type ? (type)expression : (type)null 

पहले संस्करण का (संकार्य के रूप में) ...

string str1 = strAsObject as string; 
if (str1 != null) 
{ 
    this.blabla(str1); 
} 

...इस आईएल कोड को संकलित करता है:

L_0009: ldloc.1 
L_000a: isinst string 
L_000f: stloc.2 
L_0010: ldloc.2 
L_0011: ldnull 
L_0012: ceq 
L_0014: stloc.s CS$4$0000 
L_0016: ldloc.s CS$4$0000 
L_0018: brtrue.s L_0024 
L_001a: nop 
L_001b: ldarg.0 
L_001c: ldloc.2 
L_001d: call instance void TestWinFormsApplication001.Form1::blabla(string) 
L_0022: nop 
L_0023: nop 

... और दूसरा संस्करण ...

if (strAsObject is string) 
{ 
    string str2 = (string) strAsObject; 
    this.blabla(str2); 
} 

(संकार्य + डाली है) ... इस आईएल कोड को संकलित करता है:

L_0024: ldloc.1 
L_0025: isinst string 
L_002a: ldnull 
L_002b: cgt.un 
L_002d: ldc.i4.0 
L_002e: ceq 
L_0030: stloc.s CS$4$0000 
L_0032: ldloc.s CS$4$0000 
L_0034: brtrue.s L_0047 
L_0036: nop 
L_0037: ldloc.1 
L_0038: castclass string 
L_003d: stloc.3 
L_003e: ldarg.0 
L_003f: ldloc.3 
L_0040: call instance void TestWinFormsApplication001.Form1::blabla(string) 
L_0045: nop 
L_0046: nop 

... तो आप केवल castclass कोड L_0038 में अतिरिक्त अंतर देखते हैं।

9

कुछ चीजें सीधे सेट करने के लिए:

प्रकार कास्टिंग किया जाना चाहिए जब आप सुनिश्चित करें कि ऑब्जेक्ट प्रकार आप के लिए कास्टिंग कर रहे हैं की है। यह शून्य हो सकता है (उस स्थिति में, शून्य वापस लौटाया जाएगा, जब तक कि यह एक वैल्यू प्रकार नहीं है जिसे आप कास्टिंग कर रहे हैं)

जब आप सुनिश्चित नहीं हैं, तो "as" ऑपरेटर का उपयोग किया जा सकता है। जब वस्तु जाली योग्य नहीं होती है, या ऑब्जेक्ट शून्य है, शून्य वापस कर दिया जाएगा।

ऑपरेटर, एक समर्पित आईएल बयान ( isinst) करने के लिए अनुवाद करते समय एक प्रकार डाली castclass आईएल बयान करने के लिए अनुवाद, तो यह क्रम में बनाया गया है "के रूप में"। कंपाइलर बस सही आईएल स्टेटमेंट उत्सर्जित करता है।

+0

हाँ, यह वास्तव में सही है। उपरोक्त वोट दिया गया है, क्योंकि आप यहां स्पष्टीकरण के लिए अधिकतर क्रेडिट के लायक हैं। – Noldorin

+0

मैं एक नया निर्माण करने के बजाय आपका उत्तर संपादित कर दूंगा, लेकिन मुझे ऐसा करने की अनुमति नहीं है (अभी तक) :-) –

5

इस प्रश्न का पहले ही उत्तर दिया जा चुका है, हालांकि अब तक इसमें कठोर संख्याएं गायब हैं।

Over 100000000 iterations 
AS : Failure 00:00:00.9282403 
Cast : Failure 00:00:00.9868966 
AS : Success 00:00:00.9350227 
Cast : Success 00:00:01.1382759 

आंकड़े लगातार इन अनुपात में वापस आने के

मैं करते रहे कि केवल निष्कर्ष इन आंकड़ों से ले जाना चाहते हैं देखने के एक प्रदर्शन बिंदु से, वहाँ बहुत प्राप्त किया जा करने के लिए कम है अन्य पर इन विधियों में से किसी एक को चुनकर। एक कॉल के लिए अंतर में बहुत कम है (जहां बहुत कम शून्य हो जाता है)। उस ने कहा, "जैसा" तेज़ है :)

उसके बाद, उपरोक्त आंकड़े अधिकतर कारण हैं।

"As" सफलता पर होने की तुलना में विफलता पर अधिक समय लेता है। सफलता पर कुछ नहीं होता है, मूल्य का उपयोग किया जा सकता है, या बस कॉपी किया जा सकता है। विफलता पर इसे एक शून्य संदर्भ की प्रतिलिपि बनाने के लिए एक कूद की आवश्यकता होती है।

"कास्ट" विफलता पर तेज़ है, एक कॉल "है" है और यह और नहीं करता है। सफलता पर यह बहुत धीमा है, इसमें कॉल का ओवर हेड "है" और फिर कास्ट है।

हालांकि मैं हैरान विफलता पर कास्ट विफलता के रूप में अधिक समय लेता है कि कर रहा हूँ

संपादित

अनुरोध किया के रूप में, एक आज़माएं/कैच ब्लॉक

Over 100000000 iterations 
Catch : Failure 05.05:00:00 // approximately, because I didn't hang around 
Catch : Success 00:00:01.4000952 

कोड में डाली के लिए आंकड़े जिसने आंकड़ों का पहला सेट

class Program 
{ 
    const int ITERATION_COUNT = 100000000; 
    private static UInt64 stringCount = 0; 
    private static UInt64 objectCount = 0; 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Over {0} iterations ", ITERATION_COUNT); 

     string s = "Hello"; 
     object o = new Int32(); 

     RunTest("AS : Failure {0}", TestAs, o); 
     RunTest("Cast : Failure {0}", TestIs_And_Cast, o); 
     RunTest("AS : Success {0}", TestAs, s); 
     RunTest("Cast : Success {0}", TestIs_And_Cast, s); 

     Console.WriteLine("Press any key to stop"); 
     Console.ReadKey(); 

    } 
    private static void RunTest(string testDescription, Action<object> testToRun, object arg) 
    { 
     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     for (int i = 0; i < ITERATION_COUNT; i++) 
      testToRun(arg); 
     sw.Stop(); 
     Console.WriteLine(testDescription, sw.Elapsed); 
    } 
    static void TestAs(object obj) 
    { 
     string s = obj as string; 
     if (s != null) 
      stringCount++; 
     else 
      objectCount++; 
    } 
    static void TestIs_And_Cast(object obj) 
    { 
     string s = null; 
     if (obj is string) 
     { 
      s = (string)obj; 
      stringCount++; 
     } 
     else 
      objectCount++; 
    } 
} 
+2

"as" एक कलाकार के बाद "है" से अधिक सुरुचिपूर्ण है। मैं मानता हूं कि प्रदर्शन प्रभाव नगण्य है। शायद आप अपवाद हैंडलिंग के साथ कास्ट का उपयोग कर एक टेस्ट केस भी जोड़ सकते हैं। उम्मीद है कि कुछ लोगों को यह एहसास होगा कि इस तरह की चीजों के लिए आकर्षक अपवाद "नहीं किया गया" है। :) –

+0

तो, इनमें से कितने (जैसे या कास्ट) प्रति मिलीसेकंड किया जा सकता है? यह देखते हुए कि लगभग 1 सेकंड में 100 मिलियन चेक थे: -> 100,000,000/1000 = 100,000। तो प्रति मिलीसेक * * 100 हजार या कास्ट चेक किया जा सकता है। या: प्रत्येक चेक (या तो, मोटे तौर पर) एक सेकंड के 100 मिलियन लेता है। –

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