<T> তালিকাগুলি কেন? প্রত্যেকটি তার তালিকাটি সংশোধন করার অনুমতি দেয়?


90

যদি আমি ব্যবহার করি:

var strings = new List<string> { "sample" };
foreach (string s in strings)
{
  Console.WriteLine(s);
  strings.Add(s + "!");
}

Addমধ্যে foreachএকটি InvalidOperationException ছোঁড়ার (সংগ্রহ পরিবর্তিত হয়; শুমার অপারেশন চালানো নাও করতে পারে), যা আমি যৌক্তিক বিবেচনা, যেহেতু আমরা আমাদের পায়ের নীচ থেকে কম্বল টেনে করছে।

তবে, যদি আমি ব্যবহার করি:

var strings = new List<string> { "sample" };
strings.ForEach(s =>
  {
    Console.WriteLine(s);
    strings.Add(s + "!");
  });

এটি অবিলম্বে লুপিং দ্বারা পায়ের মধ্যে নিজেকে অঙ্কুরিত না করা পর্যন্ত এটি আউটআফমিউরিএক্সেপশনটি ছুঁড়ে না ফেলে।

এটি আমার কাছে অবাক হওয়ার মতো বিষয়, কারণ আমি সবসময়ই ভাবতাম যে তালিকা.ফোরএইচ কেবল হয় foreachবা তার জন্য একটি মোড়ক for
কীভাবে এবং কেন এই আচরণের জন্য কারও কাছে ব্যাখ্যা আছে?

( জেনেরিক তালিকার জন্য ফোরইচ লুপ দ্বারা অন্তর্হিত পুনরাবৃত্তি )


7
আমি রাজী. এটি - সন্দেহজনক। আমি আপনাকে মাইক্রোসফ্ট সংযোগে পোস্ট করার বিষয়টি স্পষ্ট করে বলতে চাই এবং স্পষ্টতার জন্য জিজ্ঞাসা করি।
টমটম

4
"এটি আমার কাছে অবাক হওয়ার মতো বিষয়, কারণ আমি সবসময়ই ভেবেছিলাম যে লিস্ট। ফরচ প্রতিটি হয় কেবল foreachবা তার জন্য একটি মোড়ক for।" এটি এখনও ব্যবহার করতে পারে for। আপনি একটি forলুপে একই ক্রিয়াটি সম্পাদন করতে পারেন এবং ফলস্বরূপ একই আউটআউফমিউরিএক্সেপশন তৈরি করতে পারেন।
অ্যান্টনি পেগ্রাম

এই আমার প্রশ্ন উপর ভিত্তি করে তৈরি stackoverflow.com/q/9311272/132239 এটা বিস্তারিত মধ্যে পাওয়ার জন্য SWeko, ধন্যবাদ
Kasrak

উত্তর:


68

এটি কারণ ForEachপদ্ধতিটি এনুমरेटरটি ব্যবহার করে না, এটি লুপের সাহায্যে আইটেমগুলির মধ্য দিয়ে যায় for:

public void ForEach(Action<T> action)
{
    if (action == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    for (int i = 0; i < this._size; i++)
    {
        action(this._items[i]);
    }
}

(JustDecompile সহ কোড প্রাপ্ত)

যেহেতু গণক ব্যবহার করা হয়নি, এটি তালিকাটি পরিবর্তন হয়েছে কিনা তা কখনই পরীক্ষা করে না এবং forলুপের শেষ শর্তটি কখনই পৌঁছায় না কারণ _sizeপ্রতিটি পুনরাবৃত্তিতে বৃদ্ধি করা হয়।


হ্যাঁ, তবে কীভাবে _sizeগণনা করা হয় ? যদি এটি কেবল প্রাক-গণনা করা হয় তবে আমার উদাহরণের জন্য একবার চালানো উচিত। এটি স্পষ্টতই একরকম সতেজ হয়ে উঠেছে।
এসওয়েকো

7
এটি অ্যাড পদ্ধতিতে>> এটি.রাইটস [এটি._ সাইজ ++] = আইটেমে রিফ্রেশ করা হয়েছে;
ফ্যাবিও

4
@ সোয়েখো, এটি গণনা করা হয় না, প্রতিবার কোনও আইটেম যুক্ত করা বা অপসারণের সময় আপডেট হয়।
টমাস লেভেস্ক

4
এতে একটি _versionপ্রাইভেট ভেরিয়েবল রয়েছে List<T>যা এই ধরণের পরিস্থিতি সনাক্ত করতে পারে, কারণ এটি অপারেশনগুলিতে আপডেট হয় যা তালিকাকে নিজেরাই পরিবর্তন করে।
SWeko

আপনি প্রথমে আকারটি (int theSize = this._size) পেয়ে ব্যতিক্রমগুলি এড়াতে পারবেন, তারপরে লুপটির মধ্যে ব্যবহার করে?
ল্যাজলো

14

List<T>.ForEachforভিতরে দিয়ে বাস্তবায়ন করা হয়েছে , সুতরাং এটি গণক ব্যবহার করে না এবং এটি সংগ্রহটি পরিবর্তন করতে দেয়।


6

কারণ তালিকার শ্রেণীর সাথে সংযুক্ত ফোরইচ অভ্যন্তরীণভাবে একটি লুপ ব্যবহার করে যা এর অভ্যন্তরীণ সদস্যদের সাথে সরাসরি সংযুক্ত থাকে - যা আপনি .NET ফ্রেমওয়ার্কের জন্য উত্স কোডটি ডাউনলোড করে দেখতে পারেন।

http://references Source.microsoft.com/netframework.aspx

যেখানে ফোরচ লুপটি প্রথম এবং সর্বাগ্রে একটি সংকলক অপ্টিমাইজেশন হয় তবে পর্যবেক্ষক হিসাবে সংগ্রহের বিরুদ্ধেও পরিচালনা করতে হবে - সুতরাং সংগ্রহটি সংশোধন করা হলে এটি ব্যতিক্রম ছুঁড়ে ফেলে।


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

4
হ্যাঁ, 'নমুনা' প্রিন্ট করে Addলাইন পরিবর্তন করা strings.Insert(0, s + "!")। এটি আশ্চর্যজনক যে ডকুমেন্টেশনে এটি মোটেও উল্লেখ করা হয়নি।
SWeko

ঠিক আছে, আমি মনে করি মাইক্রোসফ্ট বুঝতে পেরেছিল যে তাদের ডকুমেন্টেশনে বিদ্যমান প্রতিটি ক্যাভ্যাট সরবরাহ করা প্রায় অসম্ভব - তাই তারা এখন তাদের উত্স কোড সরবরাহ করে। আমি দেখতে পেলাম যে সততার চেয়ে আরও ভাল সমাধান তবে আমি একমাত্র সমস্যাটি পেয়েছি যে ডাব্লুএফের মতো পণ্যগুলি দ্রুত আপডেট হয় না - 4.x ডাব্লুএফ উত্স কোড এখনও উপলভ্য নয়।
মাইক পেরেনউড

4

আমরা এই সমস্যাটি সম্পর্কে জানি, এটি যখন প্রথম লেখা হয়েছিল তখন এটি একটি তদারকি ছিল। দুর্ভাগ্যক্রমে, আমরা এটি পরিবর্তন করতে পারি না কারণ এটি এখন এই আগের কার্য কোডটি চালানো থেকে রোধ করবে:

        var list = new List<string>();
        list.Add("Foo");
        list.Add("Bar");

        list.ForEach((item) => 
        { 
            if(item=="Foo") 
                list.Remove(item); 
        });

এরিক লিপার্ট বলেছিলেন যেহেতু এই পদ্ধতির কার্যকারিতা নিজেই প্রশ্নবিদ্ধ , সুতরাং আমরা এটিকে মেট্রো স্টাইল অ্যাপ্লিকেশনগুলির জন্য (যেমন উইন্ডোজ 8 অ্যাপস) .NET এর জন্য অন্তর্ভুক্ত করি নি।

ডেভিড কেন (বিসিএল দল)


4
আমি দেখতে পাচ্ছি যে এটি একটি বড় খারাপ ব্রেকিং পরিবর্তন হবে, তবে তা এটি অস্পষ্ট উপায়ে ব্যর্থ হতে পারে এবং এটি কখনও ভাল জিনিস নয় never আমি এমন দৃশ্য দেখতে পাচ্ছি না যেখানে ফোরইচ পদ্ধতিটি ব্যবহারের জন্য সাধারণের চেয়ে সেরা (বা মূল তালিকার
ম্যাঙ্গেলিংয়ের
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.