Menu
flag Ar iconالعربيةdown icon

معدّلات الوصول في C#: public وprivate وprotected وinternal

معدّلات الوصول الستة في C# (public وprivate وprotected وinternal وprotected internal وprivate protected)، وما يسمح به كل منها، والقيم الافتراضية حين لا تكتب شيئًا، وأخطاء المترجم التي تنتجها.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

تحدد معدّلات الوصول (access modifiers) أي شيفرة تستطيع استخدام نوع أو عضو. بها يفصل الصنف الجزء الذي تعتمد عليه الشيفرة الأخرى (واجهته العامة) عن الجزء الذي يحق له تغييره (تفاصيله الداخلية). في C# ستة منها، إضافة إلى القيم الافتراضية التي تحصل عليها حين لا تكتب شيئًا.

المعدّلات الستة

المعدّلالنوع المحتوينوع مشتق، التجميع نفسهشيفرة أخرى، التجميع نفسهنوع مشتق، تجميع آخرشيفرة أخرى، تجميع آخر
publicنعمنعمنعمنعمنعم
protected internalنعمنعمنعمنعملا
protectedنعمنعملانعملا
internalنعمنعمنعملالا
private protectedنعمنعملالالا
privateنعملالالالا

التجميع (assembly) مشروع مترجم واحد: ملف .dll أو .exe الذي ينتجه. "التجميع نفسه" تعني "المشروع نفسه"، ولهذا تعمل internal بمعنى "مرئي لشيفرتي، مخفي عن مستخدمي مكتبتي".

private وpublic: التغليف

private هو الافتراضي للأعضاء والخيار الصحيح لمعظم الحقول. يكشف الصنف ما يحتاجه المستدعون عبر دوال وخصائص public، وتبقي تلك الدوال بيانات الكائن متّسقة.

المخرجات:

False
True
Priya: 180

لأن balance خاص، فالطريقتان الوحيدتان لتغييره هما Deposit وTryWithdraw، وكلتاهما تفرض القواعد. لا تستطيع أي شيفرة أخرى في البرنامج إنشاء رصيد سالب، أيًّا كانت طريقة كتابتها. هذا ما يمنحه التغليف: القواعد تعيش في مكان واحد.

private على مستوى النوع لا الكائن. يمكن لدالة في Account قراءة other.balance على مثيل Account آخر، وهكذا تُكتب عادة Equals ودوال المقارنة.

protected: مرئي للأصناف المشتقة

العضو protected مخفي عن العالم الخارجي لكنه متاح للأصناف التي ترث من الصنف المصرّح به.

المخرجات:

Sam: 4000.00
Rita: 6400.00

هناك قاعدة واحدة تفاجئ الناس. داخل Manager يمكنك استخدام baseSalary على this أو على Manager آخر، لكن لا على Employee اعتباطي:

class Manager : Employee
{
    public decimal Compare(Employee other)
    {
        return baseSalary - other.baseSalary;
        // error CS1540: Cannot access protected member 'Employee.baseSalary' via a qualifier
        // of type 'Employee'; the qualifier must be of type 'Manager' (or derived from it)
    }
}

السبب: قد يكون other من نوع Contractor مشتق أيضًا من Employee، وprotected تمنح الوصول إلى فرعك من التسلسل الهرمي، لا إلى فروع أشقائك.

الحقل المحمي يربط كل صنف مشتق بذلك الحقل إلى الأبد. تفضّل قواعد شيفرة كثيرة خاصية أو دالة protected، أو تبقي الحقول خاصة وتمنح الأصناف المشتقة ما تحتاجه فقط.

internal: مرئي داخل التجميع

يمكن لأي شيفرة في المشروع نفسه استخدام الأعضاء والأنواع internal، ولا يستطيع شيء خارجه ذلك. تستخدمها المكتبة للدوال المساعدة التي تعتمد عليها أصنافها العامة:

// In the MyShop.Pricing library project
public class PriceCalculator
{
    public decimal Total(Cart cart) => TaxRules.Apply(cart.Subtotal);
}

internal static class TaxRules   // callers of the library cannot see this class
{
    internal static decimal Apply(decimal amount) => amount * 1.2m;
}

الأنواع عالية المستوى تكون internal حين لا تكتب معدّلًا. ولهذا يكون الصنف الذي نسيت تعليمه public في مكتبة أصناف "مفقودًا" من المشروع الذي يشير إليها.

مشاريع اختبار الوحدات تجميعات منفصلة، فلا تستطيع هي أيضًا رؤية شيفرة internal. الإصلاح القياسي سمة في المكتبة:

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyShop.Pricing.Tests")]

protected internal وprivate protected

يجمع هذان المعدّلات السابقة، بطريقتين متعاكستين، ويسهل الخلط بين اسميهما:

  • protected internal هي protected أو internal: أي شيفرة في التجميع نفسه، إضافة إلى الأصناف المشتقة في تجميعات أخرى. هي الأوسع.
  • private protected (C# 7.2) هي protected و internal: فقط الأصناف المشتقة الموجودة أيضًا في التجميع نفسه. هي الأضيق، لصنف أساس يجب أن تبقى نقاط توسيعه داخل مكتبتك.
public class ReportBase
{
    protected internal string Title;      // same assembly, or subclasses anywhere
    private protected int RowLimit = 500; // subclasses in this assembly only (C# 7.2)
}

القيم الافتراضية حين لا تكتب شيئًا

المكانالافتراضيالمسموح
نوع مصرّح به في فضاء أسماءinternalpublic، internal، file (C# 11)
عضو صنفprivateالستة كلها
عضو بنيةprivatepublic، internal، private (لا يمكن وراثة البنى)
نوع متداخلprivateالستة كلها
عضو واجهةpublicالمعدّلات الصريحة مسموحة منذ C# 8
عضو تعدادpublicلا شيء

الصراحة تكلّف كلمة واحدة وتزيل سؤالًا من ذهن القارئ التالي، لذا تطلب معظم أدلة الأسلوب كتابة المعدّل حتى حين يطابق الافتراضي.

الوصول على مستوى الموصّل

يمكن للخاصية أو المفهرس منح أحد الموصّلين معدّلًا أضيق من الخاصية نفسها:

المخرجات:

report.pdf: 100%

يجب أن يكون معدّل الموصّل أكثر تقييدًا من معدّل الخاصية، ولا يمكن أن يملك معدّلًا إلا واحد من الموصّلين.

الوصول غير المتّسق

لا يمكن لعضو عام أن يكشف نوعًا أقل ظهورًا منه، لأن المستدعين سيتلقون شيئًا لا يُسمح لهم بتسميته:

internal class Discount { }

public class Checkout
{
    public Discount Current() => null;
    // error CS0050: Inconsistent accessibility: return type 'Discount' is less accessible than method 'Checkout.Current()'
}

القاعدة نفسها تعطي CS0051 لأنواع المعاملات وCS0053 لأنواع الخصائص. أصلحها بجعل النوع مرئيًا بقدر العضو، أو العضو مخفيًا بقدر النوع.

اختيار معدّل

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

الأسئلة الشائعة

ما هي معدّلات الوصول في C#؟

هناك ستة: public (أي شيفرة)، وprivate (النوع المحتوي فقط)، وprotected (النوع المحتوي والأنواع المشتقة منه)، وinternal (أي شيفرة في التجميع نفسه)، وprotected internal (التجميع نفسه، أو الأنواع المشتقة في أي مكان)، وprivate protected (الأنواع المشتقة في التجميع نفسه، C# 7.2). وأضافت C# 11 المعدّل file للأنواع المرئية في ملف مصدر واحد فقط.

ما هو معدّل الوصول الافتراضي في C#؟

أعضاء الصنف أو البنية (الحقول والدوال والخصائص والأنواع المتداخلة) تكون private افتراضيًا. والأنواع عالية المستوى (صنف مصرّح به مباشرة في فضاء أسماء) تكون internal افتراضيًا. أما أعضاء الواجهات وأعضاء التعدادات فعامة.

ماذا تعني protected في C#؟

العضو protected مرئي داخل صنفه وداخل أي صنف مشتق منه، لكن لا لشيفرة أخرى. لا يستطيع الصنف المشتق استخدامه إلا عبر نوعه الخاص: داخل Manager تعمل this.baseSalary، لكن الوصول إلى baseSalary على كائن Employee آخر هو الخطأ CS1540.

ما هو internal في C#؟

يجعل internal النوع أو العضو مرئيًا لكل الشيفرة في التجميع نفسه (ملف .dll أو .exe المترجم للمشروع نفسه) وغير مرئي خارجه. هكذا تبقي المكتبة الأصناف المساعدة خارج واجهتها العامة. وتتيح [assembly: InternalsVisibleTo("MyLib.Tests")] لمشروع اختبار أن يراها أيضًا.

كيف أصلح "is inaccessible due to its protection level"؟

هذا هو الخطأ CS0122: الشيفرة تستخدم عضوًا غير مسموح لها برؤيته، غالبًا حقلًا تُرك على الافتراضي private. إن كان يجب على الشيفرة الخارجية قراءته فاكشف خاصية أو دالة عامة؛ لا تجعل الحقل عامًا ببساطة. وإن كان نوعًا من مشروع آخر فهو على الأرجح internal.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن