محتويات الدورة

C# / المتقدم: الأعمار والتزامن وتصميم التنفيذ / الدرس 16

تصميم الواجهات والثبات والتوافق

حدد ما يحفظه المستدعي ويعدله وينتظره ويفحصه حتى لا تكسر تغييرات صحيحة نوعيا عقد السلوك.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • تحديد الملكية وعمق اللقطة.
  • اختيار التحقق وفئات الخطأ عند الحدود.
  • مراجعة التوافق بما يتجاوز التوقيع.

تعد الواجهة بسلوك وأنواع معا

يشمل العقد القيم وnull والترتيب والاستثناء والتعديل والتزامن والإلغاء والملكية. قد يكسر تغييرها المستدعي مع ثبات التوقيع. ضع الوعد قرب العملية واجعل تعليق التنفيذ لحفظ الثابت. قد يعتمد المستدعي على عدم الحجب أو على عدم تعديل المدخل مثل اعتماده على نوع الإرجاع نفسه.

لا تكشف كل مجموعة ومساعد داخلي؛ يسهل اختبار الصغير وتطويره. اشتق الواجهات من مستهلك فعلي لا تخمين. يحتاج أثر المنشئ ملكية واضحة؛ فبدء عامل دون مقبض اكتمال التزام لا يديره المستدعي. يساعد تقليل ما يكشفه النوع على تغيير تفاصيله الخاصة دون تحويل كل تحسين داخلي إلى كسر عام.

نسخ ما تعد به اللقطة

ينسخ المثال الأعداد لتخزين خاص ويكشف مغلف قراءة للمصفوفة الخاصة. لا يغير الأصل اللاحق الملتقط. تكفي عناصر int للاستقلال وتحتاج المراجع المتغيرة سياسة أخرى. يستقل المثال لأن العناصر أعداد، ولا ينبغي استخدام النتيجة لإثبات أن نسخ مراجع Customer يلتقط حقولها.

يقيد المغلف التعديل العادي ويعتمد الضمان على عدم تسريب اسم آخر. وثق المزامنة عند مشاركة المصدر؛ فالنسخ أثناء كتابة ليس لقطة متماسكة تلقائيا. إذا كانت البيانات مشتركة فلابد من أخذ اللقطة في نقطة متماسكة يحميها العقد، لا من تجميع قراءات صحيحة فرديا.

csharp لقطة أعداد ذات ملكية خاصة
using System;
using System.Collections.Generic;
using System.Linq;

var source = new List<int> { 1, 2 };
var snapshot = new Snapshot(source);
source[0] = 9;
Console.WriteLine(string.Join(",", snapshot.Values));

internal sealed class Snapshot
{
    public IReadOnlyList<int> Values { get; }
    public Snapshot(IEnumerable<int> values)
    {
        Values = Array.AsReadOnly(values.ToArray());
    }
}
الناتج المتوقع
1,2

يلتقط المنشئ الواحد والاثنين قبل تعديل المصدر.

تمثيل غير الصالح دون التباس عرضي

اختر الاستثناء للفشل الاستثنائي والنتيجة للرفض المتوقع حيث يناسب. تحدد Try خرج false، وتقلل نتيجة مصممة التركيبات الغامضة كنجاح دون مطلوب. ينبغي للتصميم تقليل تخمين الحالة. لا ينبغي أن يجمع نوع النتيجة حالات متناقضة يفسرها كل مستدع بطريقة مختلفة؛ صمم نجاحه وفشله بوضوح.

يجمع المثال التحليل والمجال خلف Try بثقافة ونمط للبروتوكول. يرفض NumberStyles.None علامة موجب وفراغات عمدا؛ وهذا قرار تنسيق لا تفضيل عام لكل نموذج مستخدم. قد يقبل نموذج تفاعلي الفراغ أو علامة الموجب، لكن بروتوكولا صارما يمكن أن يرفضهما؛ الاختلاف يجب أن يكون مقصودا.

csharp عقد عدد صارم محدود
using System;
using System.Globalization;

bool accepted = TryCount("42", out int count);
Console.WriteLine($"accepted={accepted} count={count}");
Console.WriteLine($"suffix={TryCount("42x", out _)}");

static bool TryCount(string text, out int count)
{
    count = 0;
    if (!int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out int value)) return false;
    if (value > 100) return false;
    count = value;
    return true;
}
الناتج المتوقع
accepted=True count=42
suffix=False

يقبل السجل العشري الكامل42 ويرفض42x بدل قبول بادئته.

قد يكسر تغيير يبدو أسلم المستهلكين

يحتاج تحويل الحي للّقطة وإضافة استثناء وتغيير null والفراغ مراجعة توافق؛ قد يحسن التصميم مع حاجة انتقال. وثق الفئات الآلية لتجنب النص العرضي. قد تحتاج تحسينات التصميم انتقالا للمستهلكين حتى لو بدت أكثر أمانا في عزلة؛ اختبر الاستخدام القديم لا المشروع الحالي فقط.

قد تغير الأحمال الزائدة اختيار النداء، وتختلف آثار الافتراضي الاختياري بين المعاد ترجمته والثنائي القديم. راجع توافق المصدر والثنائي وفق التوزيع الفعلي؛ لا يكفي بناء المشروع الحالي لكل تعديل. تختلف إعادة الترجمة عن تحميل ثنائيات قديمة، لذلك تعتمد مراجعة التوافق على كيفية توزيع المكتبة فعلا.

توضيح وعود اللاتزامن والتخلص

حدد متى ينتهي استخدام المدخل المستعار في Task وهل يترك الإلغاء أثرا جزئيا. عين مالك IDisposable وصلاحية ما بعده، وحالة الدفق المستعار أوالمحفوظ أوالمغلق. هذه أهم غالبا من الاسم. ينبغي أن يستطيع المستدعي معرفة متى ينتهي حق العملية في استخدام مخزنه، ومتى يصبح إغلاقه آمنا.

اختبر احتفاظ النتيجة وتعديل الأصل وتكرار الاجتياز والإلغاء بعد الاعتماد والتخلص بعد الاكتمال. افصل الاختبارات عن الخاص حيث يمكن؛ يسهل العقد الصغير مراجعة الأداء والأمن لاحقا. تكشف اختبارات المستهلك الحقيقي غموضا لا يظهر في اختبار حقل خاص مباشرة، مثل نتيجة يحتفظ بها ثم يعدل أصلها.

الأخطاء الشائعة وإصلاحها

تتغير نتيجة قراءة عبر الأصل.

لماذا يحدث؟
كشفت الواجهة منظورا بدل لقطة.
كيف تصلحه؟
انسخ بالملكية والمزامنة المقصودتين.
كيف تتجنب تكراره؟
اختبر التعديل بعد الإنشاء.

تعيد Try فشلا ويستخدم المتصل افتراضا قديما.

لماذا يحدث؟
لم يوثق الخرج عند الفشل.
كيف تصلحه؟
حدد معناه واختبره.
كيف تتجنب تكراره؟
افصل التعامل مع الحالتين.

يكسر إصدار ثابت التوقيع الإلغاء.

لماذا يحدث؟
أُهمل توافق السلوك.
كيف تصلحه؟
احفظ الفئات أوانقلها عمدا.
كيف تتجنب تكراره؟
أدرج العمر في الاختبارات.

اختبر فهمك

1. تعيد واجهة IEnumerable<Customer> ويطلب التقرير استقلالا ثابتا. ما الأسئلة؟

اعرض الحل المشروح

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

2. لماذا لا تتخلص المكتبة من كل Stream تتلقاه؟

اعرض الحل المشروح

لا ينقل المعامل الملكية وقد يحتاجه المستدعي لاحقا فينكسر التركيب. حدد الاستعارة والملكية واختر leaveOpen. يملك الفاتح التخلص غالبا وتوثق مكتبة تعيد دفقا جديدا مغلق نتيجته.

أهم ما تعلمته

  • يشمل التوافق الملكية والتوقيت وnull والأخطاء.
  • القراءة فقط والاستقلال والثبات ضمانات منفصلة.
  • أظهر الحالات غير الصالحة والتزامات العمر بالعقد.

المراجع الرسمية