الـ ArrayList هو نوع بيانات مهم في C#، بيُعتبر واحد من الـ Non-Generic Collections وموجود في الـ namespace اللي اسمه System.Collections.

الـ ArrayList بيساعدك تتعامل مع مجموعة من العناصر بمرونة أكبر من الـ Array العادي، وبيحل كتير من المشاكل اللي كانت بتواجهنا معاه.

Key Differences: Array vs. ArrayList

قبل ما ندخل في تفاصيل الـ ArrayList، خلينا نقارنه بالـ Arrays in CSharp العادي عشان نفهم الفروقات الأساسية.

FeatureArrayArrayList
Sizeحجم ثابت (Fixed Length).حجم متغير (Variable Length)، بيزيد ويقل ديناميكيًا.
Type Safetyآمن من ناحية النوع (Strongly Typed)، بيخزن نوع واحد بس.غير آمن (Not Type-Safe)، بيقدر يخزن أنواع مختلفة.
Performanceأداء أسرع لعدم وجود Boxing/Unboxing.أداء أبطأ نسبيًا بسبب عمليات الـ Boxing/Unboxing.
Flexibilityصعب تضيف أو تحذف عناصر من النص.سهل جدًا تضيف أو تحذف عناصر من أي مكان.

How ArrayList Works: Cs Boxing and Unboxing

السبب الرئيسي إن ArrayList بيقدر يخزن أي نوع بيانات هو إنه بيحول أي عنصر بيتحط جواه لنوع object. العملية دي ليها تأثير مهم على الأداء.

Boxing

لما بنضيف أي value type (زي int, bool, double) جوه ArrayList، بيتم تحويله تلقائيًا لـ object. العملية دي اسمها Boxing.

int x = 5;
object obj = x; // This is Boxing

Unboxing

لما بنسترجع قيمة من ArrayList، بنحتاج نعمل العملية العكسية عشان نرجعها لنوعها الأصلي. العملية دي اسمها Unboxing وبتتطلب Explicit Casting.

object obj = 5;
int x = (int)obj; // This is Unboxing

عمليات الـ Boxing and Unboxing دي بتستهلك موارد إضافية من الذاكرة والـ processor، وده ممكن يأثر على أداء التطبيق، خصوصًا في العمليات الكبيرة والمتكررة.

Creating an ArrayList

فيه أكتر من طريقة عشان ننشئ ArrayList:

  1. الـ Empty ArrayList: بينشئ ArrayList فاضي بالـ capacity الافتراضية.
    ArrayList arrayList = new ArrayList();
  2. الـ With Capacity: بينشئ ArrayList فاضي لكن بيحدد الـ capacity الأولية بتاعته (عدد العناصر اللي يقدر يشيلها قبل ما يحتاج يزود حجمه).
    ArrayList arrayListWithCapacity = new ArrayList(10);
  3. الـ From Another Collection: بينشئ ArrayList جديد ويحط فيه عناصر من collection تانية موجودة.
    int[] myArr = { 10, 20, 30 };
    ArrayList arrayListFromCollection = new ArrayList(myArr);

Adding Elements

Add() and AddRange()

  • الـ Add(): بتضيف عنصر واحد في آخر الـ ArrayList.
  • الـ AddRange(): بتضيف مجموعة عناصر مرة واحدة من collection تانية. الـ method دي بتاخد أي collection بتطبق الـ interface اللي اسمه ICollection.
ArrayList list = new ArrayList();
 
// Add single elements of different types
list.Add(1);
list.Add("Test");
list.Add(true);
list.Add(4.5);
list.Add(null);
list.Add("Test"); // Duplicates are allowed
 
// Add a range of elements from an array
list.AddRange(new int[] { 10, 20, 30 });

Accessing and Modifying Elements

بنقدر نوصل لأي عنصر عن طريق الـ index بتاعه، زي الـ Array بالظبط.

Console.WriteLine(list[0]); // Outputs: 1
Console.WriteLine(list[1]); // Outputs: "Test"
 
// When retrieving, you need to cast it back to its original type
int firstElement = (int)list[0];
string secondElement = (string)list[1];

وبرضو نقدر نعدل قيمة أي عنصر بنفس الطريقة:

list[0] = 101; // Update the value at index 0

Iterating Through an ArrayList

لإن الـ ArrayList بيعتبر Cs Enumerable، نقدر نلف على كل عناصره باستخدام for أو foreach loops.

// Using foreach (the variable must be var or object)
foreach (var item in list) 
{
	Console.WriteLine(item);
}
 
// Using for loop with the .Count property
for (int i = 0; i < list.Count; i++)
{
    Console.WriteLine(list[i]);
}

Inserting Elements

Add() vs. Insert()

  • الـ Add(): دايمًا بتضيف العنصر في الآخر.
  • الـ Insert(): بتضيف العنصر في مكان (index) معين إنت بتحدده.
list.Insert(2, "New Value"); // Inserts "New Value" at index 2

ممكن كمان تضيف مجموعة عناصر في مكان معين باستخدام InsertRange(index, collection).

Removing Elements

عندنا أكتر من method لحذف العناصر:

  • الـ Remove(value): بتحذف أول ظهور للعنصر اللي قيمته مطابقة للقيمة اللي بتحددها.
  • الـ RemoveAt(index): بتحذف العنصر اللي في index معين.
  • الـ RemoveRange(index, count): بتحذف عدد معين من العناصر (count) بداية من index معين.
  • الـ Clear(): بتحذف كل العناصر من الـ ArrayList، لكن الـ Capacity بتاعته بتفضل زي ما هي.
// Assuming list contains: { 1, "Test", true, "Test" }
list.Remove("Test"); // Removes the first "Test", list becomes { 1, true, "Test" }
list.RemoveAt(0);    // Removes the element at index 0, list becomes { true, "Test" }
list.RemoveRange(0, 2); // Removes the first two elements

Searching and Checking

  • الـ Contains(value): بترجع true لو العنصر موجود، و false لو مش موجود.
  • الـ IndexOf(value): بترجع الـ index بتاع أول ظهور للعنصر. لو مش موجود، بترجع -1. ممكن كمان تحددله index يبدأ يدور من عنده.
bool hasTest = list.Contains("Test"); // true
int index = list.IndexOf("Test"); // 1
 
// Start searching for "Test" from index 2
int nextIndex = list.IndexOf("Test", 2); 

Other Useful Methods

  • الـ Clone(): بتعمل shallow copy من الـ ArrayList وبترجعه كـ object، فلازم نعمله cast.
  • الـ CopyTo(): بتنسخ عناصر الـ ArrayList لـ array عادية.
  • الـ Sort(): بترتب العناصر تصاعديًا باستخدام QuickSort algorithm.
ArrayList listToSort = new ArrayList() { "USA", "India", "UK" };
listToSort.Sort();
// listToSort now contains: { "India", "UK", "USA" }

بالرغم من مرونة الـ ArrayList، هي مبقتش الخيار المفضل في C# الحديثة، وده للأسباب دي:

  1. الأداء (Performance): عمليات الـ Boxing و Unboxing المستمرة بتأثر على الأداء بشكل ملحوظ في التطبيقات الكبيرة.
  2. أمان النوع (Type Safety): لإنها بتقبل أي نوع، ممكن تحصل أخطاء runtime بسبب محاولة cast نوع غلط.

الحل الأفضل والأحدث هو استخدام الـ Generic List اللي هي List<T>.

الـ List<T> بتدينا نفس المرونة الديناميكية في الحجم، لكنها strongly typed، وده بيحل مشكلة الأداء ومشاكل الـ runtime errors المتعلقة بالأنواع.