2011-04-05 11 views
9

मैं खुद को सी # पढ़ रहा हूं (मुझे अभी तक बहुत कुछ पता नहीं है)। इस सरल उदाहरण में:क्यों n.GetHashCode() काम करता है लेकिन n.GetType() फेंकता है और अपवाद?

bool?   n = null; 

Console.WriteLine("n    = {0}", n); 
Console.WriteLine("n.ToString() = {0}", n.ToString()); 
Console.WriteLine("n.GetHashCode() = {0}", n.GetHashCode()); 

// this next statement causes a run time exception 

Console.WriteLine("n.GetType()  = {0}", n.GetType()); 

सहजता से मैं समझता हूं कि GetType() विधि अपवाद क्यों फेंक देगी। इंस्टेंस एन शून्य है जो इसे समझाएगा लेकिन, मुझे n.GetHashCode() और ToString() का उपयोग करते समय एक ही कारण के लिए अपवाद क्यों नहीं मिलता?

आपकी मदद के लिए धन्यवाद,

जॉन।

+5

इसे जांचें: http://stackoverflow.com/questions/194484/whats-the-strangest-corner-case-youve-seen-in-c-or-net/194671#194671 – mookid8000

+0

नकली, महान धागा। यह इंगित करने के लिए धन्यवाद। – Hex440bx

उत्तर

14

GetHashCode() एक आभासी विधि Nullable<T> में अधिरोहित है: जब यह एक Nullable<T> मूल्य पर कहा जाता है, Nullable<T> कार्यान्वयन किसी भी मुक्केबाजी के बिना किया जाता है। इसलिए अपवाद -

GetType() एक आभासी विधि, जिसका अर्थ है कि जब यह कहा जाता है, मूल्य पहले बॉक्सिंग रहा है ... और एक "अशक्त" नल मूल्य एक अशक्त संदर्भ में परिणाम मुक्केबाजी नहीं है। हम आईएल से देख सकते हैं:

static void Main() 
{ 
    bool? x = null; 
    Type t = x.GetType(); 
} 

को संकलित किया गया है: पहले L_000f पर callvirt अनुदेश box अनुदेश:

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    .maxstack 1 
    .locals init (
     [0] valuetype [mscorlib]System.Nullable`1<bool> nullable, 
     [1] class [mscorlib]System.Type 'type') 
    L_0000: nop 
    L_0001: ldloca.s nullable 
    L_0003: initobj [mscorlib]System.Nullable`1<bool> 
    L_0009: ldloc.0 
    L_000a: box [mscorlib]System.Nullable`1<bool> 
    L_000f: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() 
    L_0014: stloc.1 
    L_0015: ret 
} 

महत्वपूर्ण यहाँ बिट L_000a है।

अब तुलना कि बराबर कोड बुला GetHashCode साथ:

static void Main() 
{ 
    bool? x = null; 
    int hash = x.GetHashCode(); 
} 

को संकलित करता है:

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    .maxstack 1 
    .locals init (
     [0] valuetype [mscorlib]System.Nullable`1<bool> nullable, 
     [1] int32 num) 
    L_0000: nop 
    L_0001: ldloca.s nullable 
    L_0003: initobj [mscorlib]System.Nullable`1<bool> 
    L_0009: ldloca.s nullable 
    L_000b: constrained [mscorlib]System.Nullable`1<bool> 
    L_0011: callvirt instance int32 [mscorlib]System.Object::GetHashCode() 
    L_0016: stloc.1 
    L_0017: ret 
} 

इस बार हम callvirt से पहले एक constrained अनुदेश/उपसर्ग है, जो अनिवार्य रूप से मतलब है "आप डॉन ' जब आप वर्चुअल विधि को कॉल करते हैं तो बॉक्स को टी की आवश्यकता नहीं होती है। " OpCodes.Constrained प्रलेखन से:

विवश उपसर्ग callvirt निर्देश एक समान तरीका है कि thisType एक मान प्रकार या एक संदर्भ प्रकार है की स्वतंत्र में किए जाने के लिए अनुमति देने के लिए बनाया गया है।

(अधिक जानकारी के लिए लिंक का पालन करें।)

ध्यान दें कि नल मूल्य प्रकार के रास्ते मुक्केबाजी काम भी मतलब है कि यहां तक ​​कि एक में गैर-शून्य मूल्य के लिए, आप Nullable<T> नहीं मिलेगा। उदाहरण के लिए विचार करें:

int? x = 10; 
Type t = x.GetType(); 
Console.WriteLine(t == typeof(int?)); // Prints False 
Console.WriteLine(t == typeof(int)); // Prints True 

तो आप किस प्रकार बाहर निकलना गैर-व्यर्थ शामिल प्रकार है। object.GetType() पर एक कॉल कभीNullable<T> प्रकार लौटाएगा।

+0

संक्षिप्त और ठोस उत्तर। –

+0

जॉन !! आपका बहुत बहुत धन्यवाद।मैंने आपकी पुस्तक "सी # गहराई में" सी # का उपयोग करके सी # का अध्ययन करना शुरू किया, लेकिन यह जल्दी से मेरे सिर पर हो गया। नतीजतन, मैं वीएस 2008 के "सी # प्रोग्रामिंग गाइड" में गया। आपकी व्याख्या सही समझ में आता है। धन्यवाद, जॉन – Hex440bx

+0

@ टॉमस: समय के साथ लंबे समय तक बनना, मुझे डर है - लेकिन मुझे विस्तार से जाना पसंद है :) –

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