C# / دليل حلول تحريري
حل أخطاء المجموعات والتزامن والأعمار
ميز إبطال الاجتياز وسباق الحالة المشتركة وانتهاء استعارة المورد قبل اختيار الإصلاح المناسب.
قاعدة معرفة للقراءة فقط · بلا تعليقات عامة
تعرّف على الأعراض
قد ترمي القائمة InvalidOperationException أثناء الاجتياز، أو يضيع عداد مشترك زيادات، أو يرى مستهلك غير متزامن بيانات مخزن أعيد استخدامه، أو يرمي الدفق ObjectDisposedException. تختلف العقود المسببة؛ فلا تصلح مجموعة آمنة موردا متخلصا منه، ولا تؤمن ToArray اجتيازا متزامنا غير آمن تلقائيا.
افهم الأسباب المحتملة
- قد تتغير بنية مجموعة مع مجتاز نشط، وتشترك الأسماء في قائمة أو خريطة أو عنصر داخلي بعد نسخ الخارج. وقد تخرق القراءة والكتابة المنفصلتان ثابتا مركبا، ويتجاوز المستهلك استعارة مورد مجمع عند إطلاق عمل دون انتظاره. حدد الحالة قبل تبديل الحاويات عشوائيا.
1. تتبع التخزين والملكية
سجل النسخة الفعلية وأسماءها ومجتازيها وكتابها ومالك موردها. افحص موضع التخلص من الدفق أو إعادة المصفوفة. لا يعني الاسم المحلي تخزينا مستقلا. اختزل إلى بيانات محلية واحفظ أول مكدس مفيد بدلا من كبت كل استثناء حول الحلقة.
2. فصل الاجتياز عن التعديل البنيوي
تكشف مجتازات كثيرة الإبطال البنيوي وتختلف السماحات حسب المجموعة. اجمع الإزالات أولا في قائمة ذات مالك واحد أو استخدم فهرسة مثبتة الحدود. يحقق المثال القيم المختارة قبل الإزالة، ويصح لغياب خيط آخر؛ وليس بروتوكول لقطة متزامنة عاما.
using System;
using System.Collections.Generic;
using System.Linq;
var values = new List<int> { 1, 2, 3, 4 };
int[] removals = values.Where(value => value % 2 == 0).ToArray();
foreach (int value in removals) values.Remove(value);
Console.WriteLine(string.Join(",", values));
1,3
تستقل قائمة الإزالة عن اجتياز القائمة التي تعدل لاحقا.
3. مزامنة العملية المشتركة كاملة
احم كل قارئ وكاتب بقفل واحد أو تصميم متزامن موثق. لا يصلح await النهائي تحديثات تسابقت. تؤمن ConcurrentDictionary عمليات معينة لا معاملة ContainsKey ثم تحديث تلقائيا. وقد تتكرر مصانع GetOrAdd وAddOrUpdate فلا تضع أثرا يفترض مرة واحدة فيها.
4. تمديد الاستعارة حتى الاكتمال الفعلي
قد تستخدم مهمة أو استعلام مؤجل موردا بعد عودة منشئه. انتظر ضمن النطاق أو انقل الملكية. أعد مخزن ArrayPool بعد المستعيرين وتخلص من الدفق والسمافور بعد توقف المستخدمين. تقيد ReadOnlyMemory مسارا ولا تمنع المالك من إعادة استخدام الأصل.
5. مطابقة عمق اللقطة للوعد
تنسخ ToArray وnew List قيم العناصر وقد تبقى الأهداف المتغيرة مشتركة. للّقطة المستقلة أسقط قيما ثابتة أو انسخ الحقول بالمزامنة. تقيد IReadOnlyList واجهة واحدة لا كل الأسماء. وثق الترتيب مستقلا وافرز للعرض الحتمي.
تحقق من نجاح الإصلاح
يجب أن يطبع المثال1,3. اختبر الفراغ وعدم الإزالة وإزالة الجميع والتكرار والترتيب. في المشترك نسق البداية وانتظر الجميع وافحص الثابت كاملا. وفي العمر أجل الاستهلاك بإشارة صريحة وأثبت أن التخلص أو الإعادة بعده. لا تجعل تكرار عدم الانهيار برهان سلامة عاما.
امنع تكرار المشكلة
- أبق التخزين المتغير خاصا ووثق عمق النسخ والاستعارة وافصل الاجتياز والتحديث حيث يناسب. استخدم سياسة مزامنة متماسكة ولاحظ الاكتمال قبل التحرير. راجع العودة المبكرة للمجتازين والعمل المنتظر والمستعيرين.