একটি অ্যারের থেকে জেনেরিক গণনা প্রাপ্ত করুন


92

সি # তে, কীভাবে একটি প্রদত্ত অ্যারে থেকে জেনেরিক গণক পাওয়া যায়?

নীচের কোডে, অবজেক্টগুলির MyArrayএকটি অ্যারে রয়েছে MyType। আমি MyIEnumeratorপ্রদর্শিত ফ্যাশনটি পেতে চাই , তবে মনে হয় আমি একটি খালি গণনা গ্রহণ করেছি (যদিও আমি এটি নিশ্চিত করেছি MyArray.Length > 0)।

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

শুধু কৌতুহলের বাইরে, আপনি কেন গণক পেতে চান?
ডেভিড ক্লেম্পফনার

4
@ ব্যাকওয়ার্ডস_ড্যাভ আমার ক্ষেত্রে একক থ্রেডযুক্ত পরিবেশে এমন ফাইলগুলির একটি তালিকা রয়েছে যা তাদের প্রত্যেককে একবার অ্যাসিঙ্ক পদ্ধতিতে প্রক্রিয়া করা উচিত। আমি বাড়ানোর জন্য একটি সূচক ব্যবহার করতে পারি, তবে
গণনাগুলি

উত্তর:


104

2.0+ এ কাজ করে:

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

3.5+ এ কাজ করে (অভিনব লিনকুই, কিছুটা কম দক্ষ):

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

4
লিনকিউ কোড আসলে অ্যারের জন্য একজন
গণকের

4
গুফা: যেহেতু গণনাকারীরা কেবল পঠনযোগ্য অ্যাক্সেস সরবরাহ করে তাই ব্যবহারের ক্ষেত্রে এটি কোনও বড় পার্থক্য নয়।
মেহরদাদ আফশারি

8
@ মেহরদাদ যেমন বোঝায়, LINQ/Castব্যবহারের বেশ আলাদা রানটাইম আচরণ রয়েছে, যেহেতু অ্যারের প্রতিটি উপাদান একটি অতিরিক্ত সেট MoveNextএবং Currentগণকের রাউন্ড-ট্রিপগুলির মধ্য দিয়ে যাবে এবং অ্যারেটি বিশাল হলে এটি কার্য সম্পাদনকে প্রভাবিত করতে পারে। যে কোনও ক্ষেত্রে, সমস্যাটি সম্পূর্ণরূপে এবং সহজেই এড়ানো যায় যথাযথভাবে প্রথম স্থানটিতে সঠিক গণনাকারীর দ্বারা (যেমন, আমার উত্তরে দেখানো দুটি পদ্ধতির একটি ব্যবহার করে)।
গ্লেন স্লেডেন

7
প্রথমটি আরও ভাল বিকল্প! কেউই নিজেকে "অভিনব লিনকুই" সংস্করণ দ্বারা প্রতারিত করতে দেবেন না যা পুরোপুরি অতিরিক্তভাবে প্রয়োজন।
হ্যানন

@ গ্লেনস্লেডেন এটি বিশাল অ্যারেগুলির জন্য কেবল ধীরগতি নয়, কোনও আকারের অ্যারেগুলির জন্যও ধীর। সুতরাং আপনি myArray.Cast<MyType>().GetEnumerator()যদি আপনার অন্তঃস্থলীয় লুপটি ব্যবহার করেন তবে এটি ক্ষুদ্র অ্যারেগুলির জন্যও আপনাকে উল্লেখযোগ্যভাবে ধীর করতে পারে।
এভেজেনি বেরেজভস্কি

54

Yourselfালাই বহির্মুখী লাইব্রেরি কলের জন্য যথেষ্ট কুরুচিপূর্ণ কিনা তা আপনি নিজেই স্থির করতে পারেন:

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[]তা চয়ন -generic IEnumerableতার ডিফল্ট জন্য ইন্টারফেস (অর্থাত অ স্পষ্ট) বাস্তবায়ন GetEnumerator()

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?
ডেভিড ক্লেম্পফনার

4
@ ব্যাকওয়ার্ডস_ড্যাভ হ্যাঁ, এটিই শীর্ষে সঠিক উদাহরণ এবং নীচে ভুলটির মধ্যে পার্থক্য তৈরি করে। পরীক্ষা করে দেখুন অপারেটর অগ্রগণ্যতা এর সি # ইউনারী "কাস্ট" অপারেটর।
গ্লেন স্লেডেন

24

যেহেতু আমি castালাই পছন্দ করি না, তাই একটি সামান্য আপডেট:

your_array.AsEnumerable().GetEnumerator();

AsEnumerable () কাস্টিংটিও করে, তাই আপনি এখনও theালাই করছেন :) সম্ভবত আপনি আপনার_আরএটি ব্যবহার করতে পারেন Tঅফটাইপ <T> () etGetEnumerator ();
ম্লাদেন বি।

4
পার্থক্যটি হ'ল এটি রানটাইম সময়ে করা সুস্পষ্ট কাস্টের পরিবর্তে সংকলন সময়ে সম্পন্ন একটি অন্তর্ভুক্ত কাস্ট। সুতরাং, টাইপটি ভুল হলে রানটাইম ত্রুটির পরিবর্তে আপনার সংকলনের সময় ত্রুটি থাকবে।
হ্যাঙ্ক শুল্টজ

@ হ্যাঙ্কশাল্টজ যদি টাইপটি ভুল হয় তবে your_array.AsEnumerable()প্রথম স্থানে সংকলন AsEnumerable()করতে পারবেন না যেহেতু কেবল প্রয়োগকারী প্রকারের উদাহরণগুলিতে ব্যবহার করা যেতে পারে IEnumerable
ডেভিড ক্লেম্পফনার

5

এটি যতটা সম্ভব পরিষ্কার করার জন্য আমি সংকলকটিকে সমস্ত কাজ করতে দিতে চাই। কোনও কাস্ট নেই (তাই এটি প্রকৃতপক্ষে টাইপ-নিরাপদ)। কোনও তৃতীয় পক্ষের গ্রন্থাগার (সিস্টেম.লিনক) ব্যবহার করা হয় না (কোনও রানটাইম ওভারহেড নেই)।

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

// এবং কোডটি ব্যবহার করতে:

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

এটি এমন কিছু সংকলক যাদুবিদ্যার সুবিধা নেয় যা সবকিছু পরিষ্কার রাখে।

অন্য বিষয়টি লক্ষণীয় হ'ল আমার উত্তরটি হ'ল একমাত্র উত্তর যা সংকলন-সময় চেক করবে।

অন্য যে কোনও সমাধানের জন্য যদি "আরর" প্রকারের পরিবর্তন হয়, তবে কলিং কোডটি সংকলিত হবে এবং রানটাইম ব্যর্থ হবে, যার ফলে রানটাইম বাগ হবে।

আমার উত্তরটি কোডটি সংকলন না করে এবং তাই আমার কোডটিতে একটি বাগ প্রেরণের কম সম্ভাবনা রয়েছে, কারণ এটি আমার কাছে ইঙ্গিত দেয় যে আমি ভুল টাইপটি ব্যবহার করছি।


গ্লেনস্লেডেন এবং মেহরাদাদফশারি দেখানো কাস্টিংও সংকলন-সময়ের প্রমাণ।
t3chb0t

4
@ t3chb0t না তারা নেই। রানটাইম এ কাজ করা কারণ আমরা জানি যে Foo[]প্রয়োগগুলি IEnumerable<Foo>, কিন্তু যদি কখনও পরিবর্তন হয় তবে এটি সংকলনের সময় সনাক্ত করা যাবে না। সুস্পষ্ট কাস্টস কখনই সংকলন-সময় প্রমাণ হয় না। পরিবর্তে আইনিম্যুয়াল <Foo> হিসাবে অ্যারেটি ফেরত দিন / সরবরাহ করুন অন্তর্ভুক্ত কাস্ট ব্যবহার করে যা সংকলন-সময় প্রমাণ proof
টক্সেন্ট্রন

@ টক্সানট্রন আইএনিউমারেবল <T> এর কাছে একটি স্পষ্ট কাস্ট সংকলন করতে পারে না যদি আপনি যে ধরণের প্রয়োগের চেষ্টা করছেন IEnumerable cast আপনি যখন বলেন "তবে যদি তা কখনও পরিবর্তিত হয়", আপনি কী বোঝাতে চান তার একটি উদাহরণ সরবরাহ করতে পারেন?
ডেভিড ক্লেম্পফনার

অবশ্যই এটি সংকলন করে। এটিই অবৈধপ্রকাশের জন্য। আপনার সংকলক আপনাকে সতর্ক করতে পারে, একটি নির্দিষ্ট কাস্ট কাজ না করে। ব্যবহার করে দেখুন var foo = (int)new object()। এটি কেবল সূক্ষ্ম সংকলন করে এবং রানটাইমের সময় ক্র্যাশ হয়।
টক্স্যান্ট্রন

2

আপনারআরআর.অফটাইপ ()। গেটইনুমরেটর ();

এটি আরও ভাল পারফরম্যান্স করতে পারে, যেহেতু এটিতে কেবল টাইপটি পরীক্ষা করতে হয়, এবং কাস্ট করা হয় না।


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)
    {

    }

উপরের কোডটি কী সম্পাদন করবে তা দয়া করে ব্যাখ্যা করতে পারেন>
ফানী

এর চেয়ে বেশি ভোট হওয়া উচিত! সংকলকটির অন্তর্নিহিত কাস্ট ব্যবহার করা হ'ল পরিষ্কার এবং সহজ সমাধান।
টেক্সট্রন

-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 প্রয়োগের <T> এর কম বা কম সমান ET আপনার অবশ্যই অবশ্যই এটি করা উচিত, এটির ক্ষেত্রে এই প্রচেষ্টাটি মূল্যবান। বেশিরভাগ ক্ষেত্রে তা হয় না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.