2010-07-09 8 views
27

क्या कोई इसे समझा सकता है?Enum.GetValues ​​() "var" का उपयोग करते समय नाम वापस क्यों करता है?

alt text http://www.deviantsart.com/upload/g4knqc.png

using System; 

namespace TestEnum2342394834 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //with "var" 
      foreach (var value in Enum.GetValues(typeof(ReportStatus))) 
      { 
       Console.WriteLine(value); 
      } 

      //with "int" 
      foreach (int value in Enum.GetValues(typeof(ReportStatus))) 
      { 
       Console.WriteLine(value); 
      } 

     } 
    } 

    public enum ReportStatus 
    { 
     Assigned = 1, 
     Analyzed = 2, 
     Written = 3, 
     Reviewed = 4, 
     Finished = 5 
    } 
} 
+0

विजुअल स्टूडियो का कहना है कि जब आप 'var' पर होवर करते हैं तो यह प्रकार क्या होता है? – ChrisF

+0

कोई विचार नहीं, लेकिन बहुत उपयोगी लगता है! – sbenderli

+0

@ एसबेन्द्रली - मैंने अभी जांच की है और यह 'System.Object' है, जो शायद अंतर को समझाने का कोई तरीका है। – ChrisF

उत्तर

39

Enum.GetValuesArray लौटने के रूप में घोषित किया गया है।
जिस सरणी में यह लौटाता है वह वास्तविक मान ReportStatus मानों के रूप में होता है।

इसलिए, var कीवर्ड object हो जाता है, और value चर रखती है (बॉक्स्ड) enum मान टाइप किया है।
Console.WriteLine कॉल ओवरलोड को हल करता है जो object लेता है और ऑब्जेक्ट पर ToString() पर कॉल करता है, जो, enums के लिए, नाम देता है।

आप एक int से अधिक पुनरावृति करते हैं, संकलक परोक्ष मूल्यों int को डाले, और value चर सामान्य (और गैर बॉक्स्ड) int मान रखती है।
इसलिए, Console.WriteLine कॉल अधिभार को हल करता है जो int लेता है और इसे प्रिंट करता है।

आप DateTime (या किसी भी अन्य प्रकार) के लिए int बदलते हैं, तो यह अभी भी संकलन होगा, लेकिन यह क्रम में एक InvalidCastException फेंक देते हैं।

+0

तो अंतर्निहित आईन्यूमेरेबल लौटा रूपांतरण पर निर्भर करता है, है ना? – Andreas

+3

अच्छी व्याख्या, +1। ध्यान दें कि यदि enum का अंतर्निहित प्रकार एक और संख्यात्मक प्रकार था (उदाहरण के लिए यूंट या छोटा), दूसरा foreach भी असफल हो जाएगा। –

+0

@ एंड्रियास, पहले लूप में कोई रूपांतरण नहीं चल रहा है, और दूसरे लूप पर, केवल विरासत कास्टिंग की अनुमति है। यह स्पष्ट रूप से स्पष्ट रूप से परिभाषित नहीं है और न ही स्पष्ट रूप से परिभाषित किया गया है। – Dykam

5

the MSDN documentation के अनुसार, Console.WriteLine का अधिभार जो object को आंतरिक रूप से ToString पर तर्क देता है।

जब आप foreach (var value in ...) करते हैं, अपने value चर के रूप में object (के बाद से, as SLaks points out, Enum.GetValues एक untyped Array रिटर्न) लिखा गया हो और इसलिए अपने Console.WriteLineobject.ToString जो System.Enum.ToString द्वारा ओवरराइड है बुला रहा है। और यह विधि enum के नाम देता है।

जब आप foreach (int value in ...) करते हैं, तो आप enum मानों को int मानों (object के बजाय) कास्टिंग कर रहे हैं; इसलिए Console.WriteLineSystem.Int32.ToString पर कॉल कर रहा है।

+0

हां, 'foreach (ReportStatus' नामों को प्रिंट करता है और प्रिंट करता है। –

2

जब आप Console.WriteLine का उपयोग करते हैं तो आप प्रत्येक तत्व पर ToString() को निहित रूप से कॉल करते हैं।

और जब आप कहते हैं कि आप एक int (स्पष्ट प्रकार का उपयोग करके) चाहते हैं तो यह इसे एक int - और फिर ToString() में परिवर्तित कर देगा।

पहले एक Enum मूल्य ToString है() 'एड

0

एक गणना प्रकार एक पूर्णांक से अलग है। आपके नमूने में, var int का मूल्यांकन नहीं करता है, यह गणना प्रकार का मूल्यांकन करता है। यदि आपने गणना प्रकार का उपयोग किया था तो आपको वही आउटपुट मिल जाएगा।

गणित प्रकार मुद्रित होने पर नाम का उत्पादन करते हैं, न कि उनके मूल्य।

+2

बंद करें, लेकिन' var' गणना प्रकार का मूल्यांकन नहीं करता है, वास्तव में; यह 'ऑब्जेक्ट' का मूल्यांकन करता है (SLaks का उत्तर देखें) –

+2

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

0

var value वास्तव में एक enum मान (प्रकार रिपोर्टस्टैटस का प्रकार है), तो आप enumValue.ToString() का मानक व्यवहार देखते हैं - यह नाम है।

संपादित करें:
जब आप एक Console.WriteLine(value.GetType()) कर आप कि यह वास्तव में एक 'ReportStatus' है, हालांकि यह एक सादे Object में बॉक्सिंग रहा है देखेंगे।

+1

गलत। 'var' यहां 'ऑब्जेक्ट' बन जाता है। – SLaks

+0

यह उत्तर वास्तव में गलत नहीं है, हालांकि एसएलएक्स के जवाब के रूप में पूरी तरह से नहीं है। वैल्यू वेरिएबल वास्तव में रिपोर्टस्टैटस टाइप करने वाला है, यह केवल संकलक है जो वस्तु को var का मूल्यांकन करता है क्योंकि यह निर्धारित करने में सक्षम नहीं है Enum.GetValues ​​द्वारा लौटाए गए सरणी का विशिष्ट प्रकार। हालांकि, रनटाइम परिणामों पर '(मान रिपोर्टस्टैटस) का मूल्यांकन सही है। चाहे या नहीं वैल्यू वैरिएबल एक ऑब्जेक्ट मुक्केबाजी है जो रिपोर्टस्टैटस है या वास्तव में यह रिपोर्टस्टैटस वास्तव में व्यवहार के बारे में पूछे जाने वाले व्यवहार से अप्रासंगिक है। –

3

Fwiw, यहाँ Enum.GetValues ​​से disassembled कोड है() (परावर्तक के माध्यम से):

[ComVisible(true)] 
public static Array GetValues(Type enumType) 
{ 
    if (enumType == null) 
    { 
     throw new ArgumentNullException("enumType"); 
    } 
    if (!(enumType is RuntimeType)) 
    { 
     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "enumType"); 
    } 
    if (!enumType.IsEnum) 
    { 
     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType"); 
    } 
    ulong[] values = GetHashEntry(enumType).values; 
    Array array = Array.CreateInstance(enumType, values.Length); 
    for (int i = 0; i < values.Length; i++) 
    { 
     object obj2 = ToObject(enumType, values[i]); 
     array.SetValue(obj2, i); 
    } 
    return array; 
} 

हर किसी var बारे में क्या कह एक object जा रहा है और नाम लौटने object.ToString() कॉल कर रहा है सही है की तरह लग रहा ...

+0

अब कुछ s ## t stirrer आपके पास डिस्सेबल कोड पोस्ट करने के लिए होगा ... वैसे भी +1। – Mau

+0

एमएस विरोधी विघटन करने पर सभी की स्थिति है, वे आसानी से पुस्तकालयों को खराब कर सकते हैं ... –

1

संपादित करें: कुछ नमूना कोड जो कि कई (शायद सभी?) सरणी पर पुनरावृत्त करने के संभावित तरीकों की खोज करता है।

एनम प्रकार डिफ़ॉल्ट रूप से int से "व्युत्पन्न" माना जाता है। आप इस तरह के बाइट, लघु, लंबे, आदि

दोनों ही मामलों में के रूप में, यदि आप चाहते अन्य पूर्णांक प्रकारों में से एक से प्राप्त करने के लिए चुन सकते हैं, Enum.GetValues करने के लिए कॉल ReportStatus ऑब्जेक्ट की श्रृंखला लौटा रहा है।

पहले लूप में विविध कीवर्ड का उपयोग करने से संकलक को निर्दिष्ट प्रकार के सरणी का उपयोग करने के लिए कहा जाता है, जो कि रिपोर्ट वैरिएबल है, जो मान चर के प्रकार को निर्धारित करने के लिए है। Enums के लिए ToString कार्यान्वयन enum प्रविष्टि का नाम वापस करना है, न कि पूर्णांक मूल्य का प्रतिनिधित्व करता है, यही कारण है कि नाम पहले लूप से आउटपुट हो रहे हैं।

दूसरे पाश में एक इंट चर का उपयोग करने से मान Enum.GetValues द्वारा लौटाए गए मानों को रिपोर्टस्टैटस से int में परिवर्तित रूप से परिवर्तित किया जा सकता है। एक int पर कॉलिंग ToString, निश्चित रूप से, एक स्ट्रिंग को पूर्णांक मान का प्रतिनिधित्व करते हैं। अंतर्निहित रूपांतरण व्यवहार में अंतर का कारण बनता है।

अपडेट: जैसा कि अन्य ने इंगित किया है, Enum.GetValues ​​फ़ंक्शन ऐरे के रूप में टाइप की गई ऑब्जेक्ट देता है, और नतीजतन यह ऑब्जेक्ट प्रकारों का एक गणना है, रिपोर्टस्टैटस प्रकार नहीं।

भले ही, अंतिम परिणाम एक ही है सरणी या अधिक पुनरावृत्ति कि क्या ReportStatus []:

class Program 
{ 
    enum ReportStatus 
    { 
     Assigned = 1, 
     Analyzed = 2, 
     Written = 3, 
     Reviewed = 4, 
     Finished = 5, 
    } 

    static void Main(string[] args) 
    { 
     WriteValues(Enum.GetValues(typeof(ReportStatus))); 

     ReportStatus[] values = new ReportStatus[] { 
      ReportStatus.Assigned, 
      ReportStatus.Analyzed, 
      ReportStatus.Written, 
      ReportStatus.Reviewed, 
      ReportStatus.Finished, 
     }; 

     WriteValues(values); 
    } 

    static void WriteValues(Array values) 
    { 
     foreach (var value in values) 
     { 
      Console.WriteLine(value); 
     } 

     foreach (int value in values) 
     { 
      Console.WriteLine(value); 
     } 
    } 

    static void WriteValues(ReportStatus[] values) 
    { 
     foreach (var value in values) 
     { 
      Console.WriteLine(value); 
     } 

     foreach (int value in values) 
     { 
      Console.WriteLine(value); 
     } 
    } 
} 

बस कुछ अतिरिक्त मनोरंजन के लिए, मैं निर्दिष्ट से अधिक बार-बार दोहराना के कई अलग अलग तरीकों का प्रदर्शन नीचे कुछ कोड जोड़ दिया है एक फोरैच लूप के साथ सरणी, जिसमें टिप्पणियां शामिल हैं जो विस्तार से बताती हैं कि प्रत्येक मामले में क्या हो रहा है।

class Program 
{ 
    enum ReportStatus 
    { 
     Assigned = 1, 
     Analyzed = 2, 
     Written = 3, 
     Reviewed = 4, 
     Finished = 5, 
    } 

    static void Main(string[] args) 
    { 
     Array values = Enum.GetValues(typeof(ReportStatus)); 

     Console.WriteLine("Type of array: {0}", values.GetType().FullName); 

     // Case 1: iterating over values as System.Array, loop variable is of type System.Object 
     // The foreach loop uses an IEnumerator obtained from System.Array. 
     // The IEnumerator's Current property uses the System.Array.GetValue method to retrieve the current value, which uses the TypedReference.InternalToObject function. 
     // The value variable is passed to Console.WriteLine(System.Object). 
     // Summary: 0 box operations, 0 unbox operations, 1 usage of TypedReference 
     Console.WriteLine("foreach (object value in values)"); 
     foreach (object value in values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 2: iterating over values as System.Array, loop variable is of type ReportStatus 
     // The foreach loop uses an IEnumerator obtained from System.Array. 
     // The IEnumerator's Current property uses the System.Array.GetValue method to retrieve the current value, which uses the TypedReference.InternalToObject function. 
     // The current value is immediatly unboxed as ReportStatus to be assigned to the loop variable, value. 
     // The value variable is then boxed again so that it can be passed to Console.WriteLine(System.Object). 
     // Summary: 1 box operation, 1 unbox operation, 1 usage of TypedReference 
     Console.WriteLine("foreach (ReportStatus value in values)"); 
     foreach (ReportStatus value in values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 3: iterating over values as System.Array, loop variable is of type System.Int32. 
     // The foreach loop uses an IEnumerator obtained from System.Array. 
     // The IEnumerator's Current property uses the System.Array.GetValue method to retrieve the current value, which uses the TypedReference.InternalToObject function. 
     // The current value is immediatly unboxed as System.Int32 to be assigned to the loop variable, value. 
     // The value variable is passed to Console.WriteLine(System.Int32). 
     // Summary: 0 box operations, 1 unbox operation, 1 usage of TypedReference 
     Console.WriteLine("foreach (int value in values)"); 
     foreach (int value in values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 4: iterating over values as ReportStatus[], loop variable is of type System.Object. 
     // The foreach loop is compiled as a simple for loop; it does not use an enumerator. 
     // On each iteration, the current element of the array is assigned to the loop variable, value. 
     // At that time, the current ReportStatus value is boxed as System.Object. 
     // The value variable is passed to Console.WriteLine(System.Object). 
     // Summary: 1 box operation, 0 unbox operations 
     Console.WriteLine("foreach (object value in (ReportStatus[])values)"); 
     foreach (object value in (ReportStatus[])values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 5: iterating over values as ReportStatus[], loop variable is of type ReportStatus. 
     // The foreach loop is compiled as a simple for loop; it does not use an enumerator. 
     // On each iteration, the current element of the array is assigned to the loop variable, value. 
     // The value variable is then boxed so that it can be passed to Console.WriteLine(System.Object). 
     // Summary: 1 box operation, 0 unbox operations 
     Console.WriteLine("foreach (ReportStatus value in (ReportStatus[])values)"); 
     foreach (ReportStatus value in (ReportStatus[])values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 6: iterating over values as ReportStatus[], loop variable is of type System.Int32. 
     // The foreach loop is compiled as a simple for loop; it does not use an enumerator. 
     // On each iteration, the current element of the array is assigned to the loop variable, value. 
     // The value variable is passed to Console.WriteLine(System.Int32). 
     // Summary: 0 box operations, 0 unbox operations 
     Console.WriteLine("foreach (int value in (ReportStatus[])values)"); 
     foreach (int value in (ReportStatus[])values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 7: The compiler evaluates var to System.Object. This is equivalent to case #1. 
     Console.WriteLine("foreach (var value in values)"); 
     foreach (var value in values) 
     { 
      Console.WriteLine(value); 
     } 

     // Case 8: The compiler evaluates var to ReportStatus. This is equivalent to case #5. 
     Console.WriteLine("foreach (var value in (ReportStatus[])values)"); 
     foreach (var value in (ReportStatus[])values) 
     { 
      Console.WriteLine(value); 
     } 
    } 
} 

- उपरोक्त नमूने में मेरी टिप्पणियां अपडेट की गईं; डबल-चेकिंग पर मैंने देखा कि System.Array.GetValue विधि वास्तव में सरणी के तत्व को निकालने और इसे System.Object के रूप में वापस करने के लिए टाइपेड रेफरेंस क्लास का उपयोग करती है। मैंने मूल रूप से लिखा था कि एक मुक्केबाजी अभियान वहां हो रहा था, लेकिन यह तकनीकी रूप से मामला नहीं है। मुझे यकीन नहीं है कि बॉक्स ऑपरेशन की तुलना किस प्रकार टाइप की गई है। TypedReference.InternalToObject; मुझे लगता है कि यह सीएलआर कार्यान्वयन पर निर्भर करता है। भले ही, मेरा मानना ​​है कि विवरण अब कम या ज्यादा सही हैं।

+0

अधिकतर उत्तरों की तरह, गलत। 'var'' ऑब्जेक्ट 'बन जाता है। – SLaks

+1

अनुमोदित, मैं वस्तु बनने के बारे में गलत था, लेकिन तथ्य यह है कि वैल्यू वेरिएबल एक ऑब्जेक्ट मुक्केबाजी है, enum मान वास्तव में इस सवाल के लिए अप्रासंगिक है कि व्यवहार अलग क्यों है। मैंने एक कोड उदाहरण जोड़ा है जो दर्शाता है कि व्यवहार वही है चाहे var वस्तु या var रिपोर्टस्टैटस है या नहीं। –

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

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