2012-07-03 17 views
11

के साथ IENumerable कार्यान्वित करना यह एक साधारण वाक्यविन्यास प्रश्न है, लेकिन मैं इसे समझ नहीं सकता।एक ऐरे

आम तौर पर, मैं यह कर जाएगा:

public class OrderBook : IEnumerable<PriceLevel> 
{ 
    private readonly List<PriceLevel> PriceLevels = new List<PriceLevel>(); 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 

लेकिन एक सूची के बजाय, मैं एक सरणी का उपयोग करना चाहते - इस तरह:

public class ArrayOrderBook : IEnumerable<PriceLevel> 
{ 
    private PriceLevel[] PriceLevels = new PriceLevel[500]; 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 

IEnumerator IEnumerable.GetEnumerator() ठीक संकलित करने के लिए लगता है - लेकिन सार्वजनिक IEnumerator<PriceLevel> कहता है कि मुझे किसी प्रकार की कास्ट की आवश्यकता है - ऐसा करने का सबसे अच्छा तरीका क्या है?

विलियम

+2

क्यों? इसके लिए एक सरणी का उपयोग क्यों करें? – Oded

+1

'सूची' का उपयोग एक सरणी द्वारा स्वयं किया जाता है, इसलिए आप अपने काम के एक ओवरकंपिकेशन को छोड़कर कुछ हासिल नहीं कर रहे हैं। – Tudor

+1

@ ट्यूडर कक्षा में कौन सा तर्क चलाता है, इस पर निर्भर करता है, यह 'प्राइसलेवल' के लिए एक सरणी (उदाहरण के लिए एक निश्चित आकार) के लिए अधिक समझ सकता है। उसमें दोबारा प्रतिक्रिया करने के लिए कुछ भी गलत नहीं है। –

उत्तर

14

इस प्रयास करें:

public class ArrayOrderBook : IEnumerable<PriceLevel> 
{ 
    private PriceLevel[] PriceLevels = new PriceLevel[500]; 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.AsEnumerable().GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 
+1

इस प्रकार का अनुमान लगाया जा सकता है। '.अनुक्रम योग्य() 'ठीक काम करता है। 'टी [] 'लागू' IENumerable ', लेकिन 'GetEnumerator' के लिए इसकी सार्वजनिक विधि एक कमजोर टाइप किए गए 'IENumerator' को लौटाती है। –

+0

@TimS। आप बिल्कुल सही कह रहे है! सबसे व्यापक उत्तर के लिए –

6

आप अपने खुद के IEnumerable<T> कार्यान्वयन से देख सकते हैं, तब आप इंटरफ़ेस पूरा करने के लिए विधि के दोनों एक सामान्य और गैर जेनेरिक वर्जन उपलब्ध कराना होगा। ऐसा करने के लिए, चूंकि विधियों के समान हस्ताक्षर होते हैं, उनमें से एक को स्पष्ट इंटरफ़ेस कार्यान्वयन की आवश्यकता होती है। List के मामले में, सामान्य संस्करण कक्षा में एक विधि है और गैर-जेनेरिक संस्करण एक स्पष्ट इंटरफ़ेस परिभाषा है, क्योंकि सामान्य संस्करण आमतौर पर अधिक उपयोगी होता है। किसी सरणी के मामले में, पहले से ही गैर-जेनेरिक संस्करण कार्यान्वयन के रूप में था, और यह बाद के संस्करण में विधि का सामान्य संस्करण जोड़ रहा था। ब्रेकिंग चेंज से बचने के लिए, सामान्य संस्करण इसके बजाय स्पष्ट इंटरफ़ेस परिभाषा है।

इस समस्या को हल करने के कई तरीके हैं। यहां तीन सरल हैं।

public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    return PriceLevels.AsEnumerable().GetEnumerator(); 
} 


public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    IEnumerable<PriceLevel> enumerator = PriceLevels; 
    return enumerator.GetEnumerator(); 
} 

public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator() 
} 
+0

+1। – phoog

4

कास्ट T[] इसी IEnumerable<T> रहे हैं:

public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator(); 
    } 
2

ECMA-335 विभाजन मैं, §8.9.1, एक वेक्टर प्रकार (T[] की तरह भी आयाम सरणी) के अनुसार IList<T> जो यह है कि तात्पर्य लागू करता है IEnumerable<T> लागू करता है। हालांकि विधियों का कार्यान्वयन स्पष्ट है, इसलिए आपको इनमें से किसी एक का उपयोग करना होगा:

विकल्प 1: केवल IList<T> पर सरणी के निहित असाइनमेंट का उपयोग करें।

private IList<PriceLevel> PriceLevels = new PriceLevel[500]; 

विकल्प 2: एक सरणी के रूप में सदस्य चर छोड़ दो, और AsEnumerable विस्तार विधि का उपयोग करें। यह एक्सटेंशन विधि एक समर्थित निहित असाइनमेंट का उपयोग करती है जो (IEnumerable<PriceLevel>)PriceLevels जैसे प्रत्यक्ष कलाकारों का उपयोग करने के लिए बेहतर है।

IEnumerator IEnumerable.GetEnumerator() 
{ 
    return PriceLevels.AsEnumerable().GetEnumerator(); 
} 

आइटम से बचने के लिए:

  1. Cast<T> विधि अपने सरणी के प्रत्येक तत्व के लिए एक अनावश्यक प्रकार की जांच का परिचय और बचा जाना चाहिए।
  2. यदि आपको गणना से केवल गैर-शून्य तत्वों को शामिल करने की आवश्यकता है, तो OfType<T> एक्सटेंशन विधि का उपयोग करना ठीक है। अन्यथा, यह विधि प्रत्येक तत्व पर एक अनावश्यक प्रकार की जांच भी पेश करती है।