C# / المتوسط: التركيب والعمل غير المتزامن / الدرس 7
العمومية وعقود المجموعات
أعد استخدام الخوارزميات مع حفظ علاقات الأنواع وحدود المجال وملكية العناصر.
في هذه الصفحة
أهداف الدرس
- شرح معاملات الأنواع والقيود المفيدة.
- اختيار تجريد المتتالية والمجموعة بالسلوك.
- فصل سلامة النوع من وعود النسخ والتزامن.
للجسم العام عمليات مفحوصة
تعبر العمومية عن علاقات أنواع دون محو الجميع إلى object. تقبل List<int> أعدادا وتعيدها دون boxing عادي لكل عنصر. يفحص الجسم وفق القيود فلا يفترض T غير المقيد حسابا أوخاصية. تسمح العلاقة الساكنة بالحفاظ على نوع العنصر في النتائج، بدلا من تحويلات object التي تؤجل فحص الخطأ.
اشتق القيد من السلوك كـIComparable<T> للترتيب. يجعل النداء قانونيا ولا يثبت ترتيبا مجاليا مفيدا لكل تنفيذ. يبقى الخطأ وnull والاتساق التزامات معنى. لا تفيد قيود إضافية تقصي الصحيح بلا حاجة. القيد يحدد ما يمكن استدعاؤه، لا ما إذا كانت المقارنة مناسبة للمعنى التجاري أو مستقرة بين الاستدعاءات.
توضيح عقد ترتيب صغير
يعيد المثال الأكبر بعقد المقارنة. يقدم int ترتيبا عدديا متسقا ويعيد التساوي الأيسر عمدا. تحفظ النتيجة T ولا تفرز مجموعة ولا تنسخ مخططا. وفي المراجع تعيد مرجع المعامل. يرجع التساوي المعامل الأيسر عمدا؛ قد يهم ذلك إذا كانت كائنات مختلفة تقارن متساوية.
وثق قبول null ولا تعتمد على اصطلاح كل CompareTo. قد تكون واجهة المجال الواحد أوضح بنوع ملموس. عمم حين تتفق الخوارزمية والدلالة فعلا. تظل سياسة null مطلوبة للمراجع حتى لو أمكن للمترجم إثبات توافر CompareTo من القيد.
using System;
Console.WriteLine($"larger={Larger(4, 9)}");
static T Larger<T>(T left, T right) where T : IComparable<T>
{
return left.CompareTo(right) >= 0 ? left : right;
}
larger=9
تختار مقارنة int التسعة ويبقى نوع الإرجاع int.
قبول القدرة المطلوبة فعلا
تعد IEnumerable<T> بالاجتياز لاCount ثابتة الكلفة أوتكرار أوفهرسة أوتخزين مستقل. تضيف IReadOnlyList<T> قراءة مفهرسة لاخلفية ثابتة. تختلف ICollection والمجموعات المتغيرة. اختر قدرة ضيقة مفيدة ولا تجتز مصدرا مجهولا مرارا لمعرفة الحجم. قد يمثل IEnumerable مصدرا بطيئا أو ذا آثار أو مرور واحد، فلا تفترض أنه مجرد قائمة في الذاكرة.
مقارن المجموعة جزء من معناها. تختلف HashSet<string> بـOrdinal عن تجاهل الحالة. اختره للمعرفات صراحة. يفسد تغير حالة المفتاح العضوية التجزئية؛ فضل الثابت واختبر حدود المساواة. ينبغي أن يختبر اختيار المقارن اختلاف الحالة والمعرفات المتقاربة لأن ذلك يغير العضوية لا العرض فقط.
تحديد الفراغ لحاوية عامة
يستخدم المثال Stack<int> للأخير أولا. تميز TryPop الفراغ دون استثناء في الفحص العادي، وتعيد منطقية وخرجا يعتمد على النجاح. يأتي الترتيب من المكدس لامن الفرز. لا ينبغي استخدام out بعد TryPop الفاشلة كعنصر حقيقي؛ المنطقية جزء لازم من النتيجة.
تنسخ الحاوية أوتخزن قيم العناصر؛ وتبقى المراجع لأهدافها. لا تعني الإزالة التخلص التلقائي من الكائن المدار. وثق ملكية عناصر IDisposable مستقلة عن العضوية. تحتاج موارد العناصر سياسة انتقال عند الإدراج والسحب، وإلا اختلطت مسؤولية الحاوية بمسؤولية مالك المورد.
using System;
using System.Collections.Generic;
var stack = new Stack<int>();
stack.Push(3);
stack.Push(8);
bool found = stack.TryPop(out int value);
Console.WriteLine($"found={found} value={value} remaining={stack.Count}");
found=True value=8 remaining=1
أحدث قيمة مدفوعة ثمانية ويبقى عنصر واحد.
توافق الأنواع ليس سلامة الحالة
ينطبق التغاير حيث يسمح التصريح فقط. تسمح بعض واجهات القراءة بتغاير المراجع بينما List<T> ثابتة؛ فيمنع إدخال Base غير مناسب عبر List<Derived>. لا تحل التعارض بإرجاع الجميع object. يمنع ثبات List إدخال قيمة من نوع أوسع في قائمة لا تقبل إلا النوع الأضيق؛ هذا سبب سلامة لا نقص مرونة عرضي.
قد يكشف المنظور المتوافق بيانات متغيرة تحتاج مزامنة. حدد توقيت الاجتياز والتعديل وعمق النسخ وnull والاستثناء. اختبر الفراغ والواحد وعنصرا مرجعيا ومقارنا يفشل إذا دعم العقد. قد تمر قيمة مرجعية عبر واجهة متغايرة دون أن يصبح التخزين ثابتا أو آمنا للمشاركة المتزامنة.
الأخطاء الشائعة وإصلاحها
تفترض دالة عامة معاملا غائبا.
- لماذا يحدث؟
- لا يوفره القيد.
- كيف تصلحه؟
- قيد السلوك أوحقن العملية.
- كيف تتجنب تكراره؟
- اشتق الواجهة من المتطلبات.
يختلف اجتياز IEnumerable مرتين.
- لماذا يحدث؟
- افتُرض التكرار دون عقد.
- كيف تصلحه؟
- اجتز مرة أوحقق ماديا عمدا.
- كيف تتجنب تكراره؟
- اختبر المصدر ذي الحالة أوالمرور الواحد.
اعتُبر سحب IDisposable تحريرا.
- لماذا يحدث؟
- اختلطت العضوية بالملكية.
- كيف تصلحه؟
- تخلص وفق سياسة المالك.
- كيف تتجنب تكراره؟
- وثق الملكية عند الإدراج والإزالة.
اختبر فهمك
1. لماذا لا تسند List<Dog> عموما إلى List<Animal>؟
اعرض الحل المشروح
ستتيح القائمة القابلة لكتابة Animal إدخال Cat ليس Dog فتخرق العقد. يمنع الثبات ذلك. قد تكشف واجهة قراءة متغايرة الحيوانات دون إدراج لكنها لا تعد بلقطة ثابتة أومستقلة.
2. صمم أول عنصر عاما لمصدر قديفرغ دون فهرسة.
اعرض الحل المشروح
اقبل IEnumerable<T> واحصل على مجتاز بـusing واستدع MoveNext مرة وأعد نجاحا والقيمة عنده. وثق خرج الفشل والرمي. لا تستدع Count ثمFirst لمجهول فقدتكرر العمل أوتستهلك حالات مختلفة.
أهم ما تعلمته
- تحدد القيود العمليات لا دلالة المجال كاملة.
- الاجتياز والفهرسة والتعديل والملكية قدرات مختلفة.
- لا تملك الحاوية العامة عناصرها وتتخلص منها تلقائيا.