एक सरणी से सामान्य प्रगणक प्राप्त करें


91

C # में, किसी दिए गए एरे से एक सामान्य एन्यूमरेटर कैसे प्राप्त किया जा सकता है?

नीचे दिए गए कोड में, वस्तुओं MyArrayकी एक सरणी है MyType। मैं MyIEnumeratorदिखाए गए फैशन में प्राप्त करना चाहता हूं , लेकिन ऐसा लगता है कि मैं एक खाली एन्यूमरेटर प्राप्त करता हूं (हालांकि मैंने इसकी पुष्टि की है MyArray.Length > 0)।

MyType[] MyArray = ... ;
IEnumerator<MyType> MyIEnumerator = MyArray.GetEnumerator() as IEnumerator<MyType>;

बस जिज्ञासा से बाहर, आप एन्यूमरेटर क्यों प्राप्त करना चाहते हैं?
डेविड क्लेम्फनर

1
@Backwards_Dave में मेरे मामले में एकल थ्रेडेड वातावरण में फ़ाइलों की एक सूची है, जिनमें से प्रत्येक को एक बार, एक Async तरीके से संसाधित किया जाना चाहिए। मैं बढ़ाने के लिए एक सूचकांक का उपयोग कर सकता हूं, लेकिन
enumerables

जवाबों:


102

2.0+ पर काम करता है:

((IEnumerable<MyType>)myArray).GetEnumerator()

3.5+ पर काम करता है (फैंसी LINQy, थोड़ा कम कुशल):

myArray.Cast<MyType>().GetEnumerator()   // returns IEnumerator<MyType>

3
LINQY कोड वास्तव में कास्ट विधि के परिणाम के लिए एक एन्यूमरेटर देता है, न कि सरणी के लिए एन्यूमरेटर ...
गुफ़ा

1
गुफ़ा: चूंकि एन्युमेरेटर्स केवल-पढ़ने के लिए केवल पहुंच प्रदान करते हैं, इसलिए यह उपयोग के मामले में बहुत बड़ा अंतर नहीं है।
मेहरदाद अफश्री

8
@Mehrdad से स्पष्ट है, का उपयोग करते हुए LINQ/Cast, काफी अलग क्रम व्यवहार के बाद से सरणी के प्रत्येक और हर तत्व का एक अतिरिक्त सेट के माध्यम से पारित हो जाएगा MoveNextऔर Currentप्रगणक राउंड ट्रिप, और यदि सरणी बहुत बड़ा है इस प्रदर्शन को प्रभावित कर सकता है। किसी भी मामले में, समस्या पूरी तरह से और आसानी से पहले स्थान पर उचित गणनाकर्ता प्राप्त करने से बचती है (यानी, मेरे उत्तर में दिखाए गए दो तरीकों में से एक का उपयोग करके)।
ग्लेन स्लेडेन

7
पहला बेहतर विकल्प है! किसी को भी "फैंसी LINQy" संस्करण द्वारा खुद को धोखा देने न दें जो पूरी तरह से शानदार है।
हेनन

@GlennSlayden यह केवल विशाल सरणियों के लिए धीमा नहीं है, यह किसी भी आकार के सरणियों के लिए धीमा है। इसलिए यदि आप myArray.Cast<MyType>().GetEnumerator()अपने अंतरतम पाश में उपयोग करते हैं, तो यह आपको छोटे सरणियों के लिए भी धीमा कर सकता है।
एव्गेनि Berezovsky

54

आप खुद तय कर सकते हैं कि कास्टिंग बदसूरत एक बाहरी लाइब्रेरी कॉल को वारंट करने के लिए पर्याप्त है:

int[] arr;
IEnumerator<int> Get1()
{
    return ((IEnumerable<int>)arr).GetEnumerator();  // <-- 1 non-local call

    // ldarg.0 
    // ldfld int32[] foo::arr
    // castclass System.Collections.Generic.IEnumerable`1<int32>
    // callvirt instance class System.Collections.Generic.IEnumerator`1<!0> System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
}

IEnumerator<int> Get2()
{
    return arr.AsEnumerable().GetEnumerator();   // <-- 2 non-local calls

    // ldarg.0 
    // ldfld int32[] foo::arr
    // call class System.Collections.Generic.IEnumerable`1<!!0> System.Linq.Enumerable::AsEnumerable<int32>(class System.Collections.Generic.IEnumerable`1<!!0>)
    // callvirt instance class System.Collections.Generic.IEnumerator`1<!0> System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
}

और पूर्णता के लिए, किसी को यह भी ध्यान रखना चाहिए कि निम्नलिखित सही नहीं है - और रनटाइम पर दुर्घटनाग्रस्त हो जाएगा - क्योंकि इसके डिफ़ॉल्ट (यानी गैर-स्पष्ट) कार्यान्वयन के लिए नॉन- जेनर इंटरफ़ेस का T[]चयन करता है ।IEnumerableGetEnumerator()

IEnumerator<int> NoGet()                    // error - do not use
{
    return (IEnumerator<int>)arr.GetEnumerator();

    // ldarg.0 
    // ldfld int32[] foo::arr
    // callvirt instance class System.Collections.IEnumerator System.Array::GetEnumerator()
    // castclass System.Collections.Generic.IEnumerator`1<int32>
}

रहस्य यह है कि, SZGenericArrayEnumerator<T>- SZArrayEnumeratorएक आंतरिक वर्ग से विरासत में क्यों नहीं मिला है जो वर्तमान में 'सील' के रूप में चिह्नित है - क्योंकि यह (सहसंयोजक) सामान्य एन्यूमरेटर को डिफ़ॉल्ट रूप से वापस करने की अनुमति देगा?


क्या कोई कारण है कि आपने अतिरिक्त कोष्ठक का उपयोग किया, ((IEnumerable<int>)arr)लेकिन केवल एक सेट कोष्ठक में (IEnumerator<int>)arr?
डेविड क्लेम्फनर

1
@ Backwards_Dave हाँ, यह वही है जो शीर्ष पर सही उदाहरणों के बीच अंतर बनाता है, और सबसे नीचे गलत। सी # अपरिपक्व "कास्ट" ऑपरेटर के ऑपरेटर पूर्वता की जांच करें ।
ग्लेन स्लेडेन

24

चूंकि मुझे कास्टिंग पसंद नहीं है, इसलिए थोड़ा अपडेट:

your_array.AsEnumerable().GetEnumerator();

AsEnumerable () भी कास्टिंग करता है, इसलिए आप अभी भी कास्ट कर रहे हैं :) हो सकता है कि आप your_array.OfType <T> () का उपयोग करें। GetEnumerator ();
मैडलेन बी।

1
अंतर यह है कि यह रनटाइम में किए गए स्पष्ट कलाकारों के बजाय संकलन समय पर किया गया एक निहित कलाकार है। इसलिए, यदि प्रकार गलत है, तो आपके पास रनटाइम त्रुटियों के बजाय समय त्रुटियों का संकलन होगा।
हांक

@HankSchultz यदि प्रकार गलत है, तो your_array.AsEnumerable()पहले स्थान पर संकलित नहीं करेगा क्योंकि AsEnumerable()इसका उपयोग केवल उन प्रकारों के उदाहरणों पर किया जा सकता है जो लागू होते हैं IEnumerable
डेविड क्लेम्फनर

5

जितना संभव हो सके इसे साफ करने के लिए मैं संकलक को सभी काम करने देना चाहता हूं। कोई जाति नहीं है (इसलिए इसका वास्तव में प्रकार-सुरक्षित)। किसी भी तीसरे पक्ष के पुस्तकालय (System.Linq) का उपयोग नहीं किया जाता है (कोई रनटाइम ओवरहेड)।

    public static IEnumerable<T> GetEnumerable<T>(this T[] arr)
    {
        return arr;
    }

// और कोड का उपयोग करने के लिए:

    String[] arr = new String[0];
    arr.GetEnumerable().GetEnumerator()

यह कुछ संकलक जादू का लाभ उठाता है जो सब कुछ साफ रखता है।

ध्यान देने वाली बात यह है कि मेरा उत्तर एकमात्र उत्तर है जो संकलन-समय जाँच करेगा।

किसी भी अन्य समाधान के लिए यदि "गिरफ्तारी" का प्रकार बदलता है, तो कॉलिंग कोड संकलन करेगा, और रनटाइम में विफल हो जाएगा, जिसके परिणामस्वरूप रनटाइम बग होगा।

मेरे जवाब से कोड संकलित नहीं होगा और इसलिए मेरे पास अपने कोड में बग को शिपिंग करने की कम संभावना है, क्योंकि यह मुझे संकेत देगा कि मैं गलत प्रकार का उपयोग कर रहा हूं।


ग्लेनसेल्डेन और मेहरदादफेशरी द्वारा दर्शाई गई कास्टिंग भी संकलन-समय प्रमाण है।
t3chb0t

1
@ t3chb0t नहीं वे नहीं हैं। रनटाइम पर काम क्योंकि हम जानते हैं कि Foo[]लागू करता है IEnumerable<Foo>, लेकिन अगर कभी भी यह बदलता है तो संकलन समय पर इसका पता नहीं चलेगा। स्पष्ट जाति कभी संकलन-समय प्रमाण नहीं है। इसके बजाय IEnumerable <Foo> के रूप में असाइन / रिटर्निंग एंजेस्ट कास्ट का उपयोग करता है जो संकलन-टाइम प्रूफ है।
Toxantron

@Toxantron IEnumerable <T> के लिए एक स्पष्ट डाली संकलित नहीं करेगा जब तक कि आप जिस प्रकार IEnumerable को लागू करने का प्रयास कर रहे हैं। जब आप कहते हैं "लेकिन अगर वह कभी बदलता है", तो क्या आप इसका एक उदाहरण प्रदान कर सकते हैं कि आपका क्या मतलब है?
डेविड क्लेम्फनर

बेशक यह संकलन करता है। यही InvalidCastException है। आपका संकलक आपको चेतावनी दे सकता है, कि एक निश्चित कलाकार काम नहीं करता है। कोशिश करो var foo = (int)new object()। यह बस ठीक संकलन करता है और रनटाइम पर क्रैश होता है।
टॉक्सेंट्रॉन

2

। YourArray.OfType () GetEnumerator ();

थोड़ा बेहतर प्रदर्शन कर सकते हैं, क्योंकि इसमें केवल प्रकार की जांच करनी है, और डाली नहीं।


आपको स्पष्ट रूप से प्रकार का उपयोग करते समय निर्दिष्ट करना होगा OfType<..type..>()- कम से कम मेरे मामले मेंdouble[][]
एम। मिम्पेन

0
    MyType[] arr = { new MyType(), new MyType(), new MyType() };

    IEnumerable<MyType> enumerable = arr;

    IEnumerator<MyType> en = enumerable.GetEnumerator();

    foreach (MyType item in enumerable)
    {

    }

क्या आप बता सकते हैं कि उपरोक्त कोड>>
फणी

यह वोट अधिक होना चाहिए! संकलक के निहित कलाकारों का उपयोग करना सबसे साफ और सबसे आसान समाधान है।
Toxantron

-1

आप क्या कर सकते हैं, ज़ाहिर है, बस सरणियों के लिए अपने स्वयं के सामान्य प्रगणक को लागू करें।

using System.Collections;
using System.Collections.Generic;

namespace SomeNamespace
{
    public class ArrayEnumerator<T> : IEnumerator<T>
    {
        public ArrayEnumerator(T[] arr)
        {
            collection = arr;
            length = arr.Length;
        }
        private readonly T[] collection;
        private int index = -1;
        private readonly int length;

        public T Current { get { return collection[index]; } }

        object IEnumerator.Current { get { return Current; } }

        public bool MoveNext() { index++; return index < length; }

        public void Reset() { index = -1; }

        public void Dispose() {/* Nothing to dispose. */}
    }
}

यह ग्लेन स्लेडेन द्वारा वर्णित SZGenericArrayEnumerator <T> के .NET इम्प्लांटेशन के बराबर या कम है। आपको केवल ऐसा करना चाहिए, ऐसे मामले हैं जहां यह प्रयास के लायक है। ज्यादातर मामलों में ऐसा नहीं है।

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