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

C# / الأساسي: البرامج ذات الأنواع وعقود الكائنات / الدرس 5

الأصناف والواجهات والثوابت

نمذج السلوك بالمنشئات والخصائص والواجهات الصغيرة دون خلط الوراثة بالملكية والثبات.

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

أهداف الدرس

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

الصنف يحدد الحالة الصالحة والعمليات

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

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

حفظ الانتقال ضمن المجال

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

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

csharp عداد غير سالب محمي
using System;

var counter = new Counter(8);
Console.WriteLine($"advanced={counter.TryAdvance()} value={counter.Value}");

internal sealed class Counter
{
    public int Value { get; private set; }
    public Counter(int value)
    {
        if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
        Value = value;
    }
    public bool TryAdvance()
    {
        if (Value == int.MaxValue) return false;
        Value++;
        return true;
    }
}
الناتج المتوقع
advanced=True value=9

يثبت المنشئ الثابت وتحفظه TryAdvance قبل عرض تسعة.

تسمي الواجهة حاجة المستهلك

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

تمثل الوراثة علاقة استبدال، وغالبا يوضح التركيب استخدام كائن لآخر. استخدم virtual وoverride للتوجيه الديناميكي وتجنب إخفاء العضو بـnew عند توقع التجاوز. تغلق sealed التوسعة عمدا. إذا لم تكن هناك علاقة استبدال حقيقية، فقد يكون تركيب مكون داخل آخر أوضح من سلسلة وراثة تخفي الاعتماد.

حقن السلوك بدلا من تثبيته

يعتمد المثال على ILabel.Name لاFixedLabel الملموس. تكفي الواجهة للتحية ويقدم الاختبار تنفيذا صغيرا دون خادم أوقاعدة أوإطار حقن. تظهر معاملات الإنشاء الاعتماد. لا يحتاج المثال إطار حقن لكي يمرر تنفيذا؛ يكفي إنشاء المكون المحدد عند حدود التطبيق.

قد تحقق أنواع القيمة الواجهات وتسبب boxing حسب الاستخدام. لا تختر class أوstruct بشعار السرعة؛ راع الهوية والتعديل والنسخ والقياس. تتعمق الدروس اللاحقة في ذلك. قد تغير مسارات الاستدعاء عبر الواجهة كلفة boxing، فلا تستنتج أداء النوع من حجمه أو اسمه فقط.

csharp اعتماد سلوكي ضيق
using System;

ILabel label = new FixedLabel("Ada");
Console.WriteLine($"hello {label.Name}");

internal interface ILabel
{
    string Name { get; }
}

internal sealed class FixedLabel : ILabel
{
    public string Name { get; }
    public FixedLabel(string name) => Name = name ?? throw new ArgumentNullException(nameof(name));
}
الناتج المتوقع
hello Ada

يلاحظ المستدعي خاصية الواجهة ويتلقى Ada من النسخة.

المساواة والنسخ خيارا تصميم

للأصناف هوية مرجع عادة ما لم تعرف المساواة، وتولد records مساواة قيمية. يبقى record class مرجعيا وتنسخ with سطحيا فقد تشارك قائمة. تقيد init إسناد الخاصية بعد الإنشاء ولا تجمد هدفها تكراريا. المساواة المولدة لا تنقل ملكية المراجع داخل السجل، كما لا يغير with أهدافها تلقائيا.

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

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

يضع setter الكائن بحالة غير صالحة.

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

تشارك نسخة with قائمة متغيرة.

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

يختلف عضو مشتق عبر مرجع الأصل.

لماذا يحدث؟
أُخفي بدلا من تجاوزه.
كيف تصلحه؟
استخدم virtual/override المقصودة.
كيف تتجنب تكراره؟
اختبر عبر النوع المعلن.

اختبر فهمك

1. هل تجعل خاصية init من List<int> القائمة ثابتة؟ أعط عقدا أقوى.

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

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

2. صمم اختبار عداد عند int.MaxValue للثابت والفشل.

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

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

أهم ما تعلمته

  • يحفظ الإنشاء والعمليات ثابتا واضحا.
  • تحتاج الواجهات وعود معنى وتطابق أعضاء.
  • لا تعني records وinit والقراءة ثباتا عميقا تلقائيا.

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