فرز List<T> في C#: من الفوضى إلى النظام في 5 دقائق
\n\nتخيل: لديك قائمة بالمستخدمين، وتحتاج إلى عرضها على الشاشة بترتيب أبجدي حسب اسم العائلة. أو قائمة بالمنتجات - فرزها حسب السعر من الأرخص إلى الأغلى. مهمة مألوفة؟ على Stack Overflow، جمع سؤال «How to Sort a List<T> by a property in the object» آلاف المشاهدات - مما يعني أن هذا الموضوع يثير اهتمام العديد من المطورين.
\n\nفي هذه المقالة، سنستعرض خمس طرق لفرز القائمة في C#. ستتعلم كيفية الفرز حسب خاصية واحدة، عدة حقول، وكذلك كيفية جعل الفرز بأسرع ما يمكن. هيا بنا!
\n\nما سنقوم بفرزه: فئة User
\n\nللأمثلة، سنأخذ نموذج بيانات بسيط - مستخدم بالاسم والعمر والتقييم.
\n\npublic class User\n{\n public string Name { get; set; }\n public int Age { get; set; }\n public double Rating { get; set; }\n\n public override string ToString()\n {\n return $"{Name} ({Age}) — {Rating:F2}";\n }\n}\n\nلننشئ قائمة اختبارية:
\n\nList<User> users = new List<User>\n{\n new User { Name = "Анна", Age = 30, Rating = 4.5 },\n new User { Name = "Борис", Age = 25, Rating = 3.8 },\n new User { Name = "Виктор", Age = 35, Rating = 4.9 },\n new User { Name = "Галина", Age = 28, Rating = 4.2 }\n};\n\nالطريقة 1: LINQ OrderBy - الأبسط والأكثر أناقة
\n\nإذا كنت تريد فرز List<T> حسب خاصية كائن بسرعة وبدون كود زائد - استخدم LINQ. طريقة OrderBy تنشئ تسلسلاً مرتباً جديداً، دون تغيير القائمة الأصلية. هذا مثالي عندما تحتاج إلى فرز "أثناء التنقل".
// الفرز حسب الاسم (تصاعدياً)\nvar sortedByName = users.OrderBy(u => u.Name).ToList();\n\n// الفرز حسب العمر (تنازلياً)\nvar sortedByAgeDesc = users.OrderByDescending(u => u.Age).ToList();\n\n// الفرز حسب عدة حقول: أولاً حسب العمر، ثم حسب التقييم\nvar sortedMulti = users\n .OrderBy(u => u.Age)\n .ThenBy(u => u.Rating)\n .ToList();\n\nالإيجابيات: قابلية القراءة، سلاسل الفرز، تعمل مع أي أنواع من الخصائص.
\nالسلبيات: تنشئ قائمة جديدة (ذاكرة إضافية).
الطريقة 2: List.Sort مع مفوض Comparison - فرز في المكان
\n\nإذا كنت بحاجة إلى فرز قائمة C# دون إنشاء نسخة (توفير الذاكرة)، استخدم طريقة Sort مع تعبير لامدا. هذه الطريقة تغير المجموعة الأصلية.
// الفرز حسب الاسم (في المكان)\nusers.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));\n\n// الفرز حسب العمر (تنازلياً)\nusers.Sort((a, b) => b.Age.CompareTo(a.Age));\n\n// الفرز حسب التقييم\nusers.Sort((a, b) => a.Rating.CompareTo(b.Rating));\n\nالإيجابيات: لا ينشئ كائنًا جديدًا، أسرع للقوائم الكبيرة.
\nالسلبيات: أقل قابلية للقراءة في الفرز المعقد.
الطريقة 3: تنفيذ IComparable - فرز "جاهز"
\n\nإذا كان يجب على فصلك دائمًا الفرز حسب نفس الحقل (على سبيل المثال، حسب الاسم)، قم بتنفيذ الواجهة IComparable<T>. عندها ستعمل List.Sort() بدون وسائط.
public class User : IComparable<User>\n{\n // ... الخصائص من المثال أعلاه ...\n\n public int CompareTo(User other)\n {\n if (other == null) return 1;\n return string.Compare(this.Name, other.Name, StringComparison.Ordinal);\n }\n}\n\n// الاستخدام\nusers.Sort(); // تلقائياً حسب الاسم\n\nالإيجابيات: فرز طبيعي لمنطق الأعمال.
\nالسلبيات: يحدد قاعدة واحدة بشكل صارم - للحقول الأخرى ستحتاج إلى كتابة منطق منفصل.