তারা যেমন বলেছে, শয়তানটি বিশদে রয়েছে ...
সংগ্রহের গণনা দুটি পদ্ধতির মধ্যে সবচেয়ে বড় পার্থক্য হ'ল foreach
রাষ্ট্র বহন করে, যেখানে ForEach(x => { })
নেই।
তবে কিছুটা গভীর খনন করতে দেয়, কারণ এমন কিছু বিষয় রয়েছে যা সম্পর্কে আপনার সচেতন হওয়া উচিত যা আপনার সিদ্ধান্তকে প্রভাবিত করতে পারে, এবং এমন কিছু বিষয় রয়েছে যা উভয় ক্ষেত্রেই কোডিংয়ের সময় আপনাকে সচেতন হওয়া উচিত।
List<T>
আচরণ পর্যবেক্ষণ করতে আমাদের সামান্য পরীক্ষায় ব্যবহার করতে দেয় । এই পরীক্ষার জন্য, আমি। নেট 4.7.2 ব্যবহার করছি:
var names = new List<string>
{
"Henry",
"Shirley",
"Ann",
"Peter",
"Nancy"
};
foreach
প্রথমে এটি দিয়ে পুনরাবৃত্তি করতে দেয় :
foreach (var name in names)
{
Console.WriteLine(name);
}
আমরা এটিকে প্রসারিত করতে পারি:
using (var enumerator = names.GetEnumerator())
{
}
হাতে থাকা গণক সহ, আমরা যে প্রচ্ছদগুলি পেয়েছি তার নিচে নজর রাখছি:
public List<T>.Enumerator GetEnumerator()
{
return new List<T>.Enumerator(this);
}
internal Enumerator(List<T> list)
{
this.list = list;
this.index = 0;
this.version = list._version;
this.current = default (T);
}
public bool MoveNext()
{
List<T> list = this.list;
if (this.version != list._version || (uint) this.index >= (uint) list._size)
return this.MoveNextRare();
this.current = list._items[this.index];
++this.index;
return true;
}
object IEnumerator.Current
{
{
if (this.index == 0 || this.index == this.list._size + 1)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
return (object) this.Current;
}
}
দুটি বিষয় তাৎক্ষণিকভাবে প্রকট হয়ে যায়:
- অন্তর্নিহিত সংগ্রহের অন্তরঙ্গ জ্ঞান সহ আমরা একটি রাষ্ট্রীয় বস্তু ফিরিয়ে আছি।
- সংগ্রহের অনুলিপি একটি অগভীর অনুলিপি।
এটি অবশ্যই কোনওভাবেই থ্রেড নিরাপদ নয়। যেমন উপরে উল্লিখিত ছিল, পুনরাবৃত্তি করার সময় সংগ্রহ পরিবর্তন করা কেবল খারাপ মোজো mo
কিন্তু পুনরাবৃত্তির সময় সংগ্রহের সাথে আমাদের বাহিরের মাধ্যমে পুনরুত্থানের সময় সংগ্রহটি কীভাবে অবৈধ হয়ে উঠবে সে সম্পর্কে কী বলা যায়? সেরা অনুশীলনগুলি ক্রিয়াকলাপ এবং পুনরাবৃত্তির সময় সংগ্রহটির সংস্করণকরণ এবং অন্তর্নিহিত সংগ্রহ কখন পরিবর্তন হবে তা সনাক্ত করতে সংস্করণগুলি পরীক্ষা করার পরামর্শ দেয়।
এখানে জিনিসগুলি সত্যিই দুর্বল হয়ে উঠেছে's মাইক্রোসফ্ট ডকুমেন্টেশন অনুযায়ী:
যদি সংযোজনে পরিবর্তনগুলি করা হয়, যেমন উপাদানগুলি যোগ করা, সংশোধন করা, বা মুছতে, তবে গণকের আচরণ নির্ধারিত।
ভাল, যে কি মানে? উদাহরণস্বরূপ, কেবলমাত্র List<T>
প্রয়োগগুলি ব্যতিক্রম হ্যান্ডলিংয়ের অর্থ এই নয় যে কার্যকর করা সমস্ত সংগ্রহগুলি IList<T>
একই কাজ করবে। এটি লিসকভ সাবস্টিটিউশন নীতিমালার সুস্পষ্ট লঙ্ঘন বলে মনে হচ্ছে:
একটি সুপার ক্লাসের অবজেক্টগুলি অ্যাপ্লিকেশনটি ভঙ্গ না করে তার সাবক্লাসের অবজেক্টগুলির সাথে প্রতিস্থাপনযোগ্য হবে।
আরেকটি সমস্যা হ'ল গণকের অবশ্যই প্রয়োগ করতে হবে IDisposable
- এর অর্থ সম্ভাব্য মেমরি ফাঁসের আরও একটি উত্স, কেবলমাত্র যদি কলার এটি ভুল করে না, তবে লেখক যদি Dispose
প্যাটার্নটি সঠিকভাবে বাস্তবায়ন না করেন ।
শেষ অবধি, আমাদের একটি আজীবন সমস্যা আছে ... যদি পুনরুক্তিযোগ্য বৈধ হয় তবে অন্তর্নিহিত সংগ্রহটি চলে যায় তবে কী ঘটে? আমরা এখন কি ছিল একটি স্ন্যাপশট ... যখন আপনি কোনও সংগ্রহশালা এবং এর পুনরাবৃত্তির জীবনকাল পৃথক করেন, আপনি সমস্যার জন্য জিজ্ঞাসা করছেন।
এখন পরীক্ষা করা যাক ForEach(x => { })
:
names.ForEach(name =>
{
});
এটি প্রসারিত:
public void ForEach(Action<T> action)
{
if (action == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
int version = this._version;
for (int index = 0; index < this._size && (version == this._version || !BinaryCompatibility.TargetsAtLeast_Desktop_V4_5); ++index)
action(this._items[index]);
if (version == this._version || !BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
return;
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
গুরুত্বপূর্ণ দ্রষ্টব্য নিম্নলিখিত:
for (int index = 0; index < this._size && ... ; ++index)
action(this._items[index]);
এই কোডটি কোনও গণককে বরাদ্দ করে না (কিছুই করার জন্য Dispose
), এবং পুনরাবৃত্তির সময় বিরতি দেয় না ।
নোট করুন যে এটি অন্তর্নিহিত সংগ্রহের অগভীর অনুলিপিও সম্পাদন করে তবে সংগ্রহটি এখন সময়ের সাথে স্ন্যাপশট। লেখক যদি সংগ্রহ বা 'বাসি' পরিবর্তনটি পরীক্ষা করে সঠিকভাবে প্রয়োগ না করেন তবে স্ন্যাপশটটি এখনও বৈধ।
এটি কোনওভাবেই আপনাকে আজীবন সমস্যাগুলির সমস্যা থেকে রক্ষা করে না ... যদি অন্তর্নিহিত সংগ্রহটি অদৃশ্য হয়ে যায় তবে আপনার কাছে এখন একটি অগভীর অনুলিপি রয়েছে যা যা ছিল তা নির্দেশ করে ... তবে কমপক্ষে আপনার কাছে একটি নেই Dispose
সমস্যা নেই অনাথ পুনরাবৃত্তিকারীদের সাথে ডিল ...
হ্যাঁ, আমি বলেছিলাম পুনরাবৃত্তিকারীরা ... কখনও কখনও এটির পক্ষে সুবিধাজনক। মনে করুন আপনি একটি ডেটাবেস কার্সারের অনুরূপ কিছু বজায় রাখতে চান ... সম্ভবত একাধিক foreach
স্টাইলের Iterator<T>
উপায়। আধ্যাত্মিক নকশার এই স্টাইলটি আমি ব্যক্তিগতভাবে অপছন্দ করি কারণ আজীবন সমস্যা রয়েছে এবং আপনি যে সংগ্রহগুলির উপর নির্ভর করছেন তার লেখকদের ভাল অনুগ্রহের উপর নির্ভর করেন (যদি না আপনি আক্ষরিকভাবে নিজেকে স্ক্র্যাচ থেকে সবকিছু না লিখে)।
সর্বদা একটি তৃতীয় বিকল্প আছে ...
for (var i = 0; i < names.Count; i++)
{
Console.WriteLine(names[i]);
}
এটি সেক্সি নয়, তবে এটির দাঁত ( টম ক্রুজ এবং মুভি দ্য ফার্মের কাছে ক্ষমাপ্রার্থী) )
এটি আপনার পছন্দ, তবে এখন আপনি জানেন এবং এটি একটি অবহিত হতে পারে।