constant and readonly in c# with example




ما هو الفرق بين const و readonly؟ (20)

ما هو الفرق بين const readonly ، وهل تستخدم واحدًا على الآخر؟


الثوابت

  • الثوابت ثابتة بشكل افتراضي
  • يجب أن يكون لها قيمة في وقت التحويل البرمجي (يمكن أن يكون لديك مثلاً 3.14 * 2 ، لكن لا يمكن الاتصال بأساليب)
  • يمكن الإعلان عنها داخل الوظائف
  • يتم نسخها في كل تجميع يستخدمها (يحصل كل تجميع على نسخة محلية من القيم)
  • يمكن استخدامها في الصفات

حقول المثيل للقراءة

  • يجب أن يكون لديك قيمة محددة ، عند خروج منشئ الوقت
  • يتم تقييمها عند إنشاء المثيل

حقول readonly ثابتة

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

ReadOnly: سيتم تهيئة القيمة مرة واحدة فقط من مُنشئ الفصل.
const: يمكن تهيئتها في أي دالة ولكن مرة واحدة فقط


أعتقد أن قيمة const هي نفسها لكل الكائنات (ويجب أن يتم تهيئتها باستخدام تعبير حرفي) ، بينما يمكن أن تكون readonly مختلفة لكل عملية إنشاء ...


الثابت هو ثابت وقت تجميع بينما يسمح للقراءة فقط بحساب قيمة في وقت التشغيل وتعيينها في مُنشئ أو مُهيئ الحقل. لذلك ، دائمًا ما تكون كلمة "const" ثابتة ، ولكن "readonly" يكون للقراءة فقط بمجرد تعيينها.

لدى Eric Lippert من فريق C # المزيد من المعلومات حول الأنواع المختلفة من ثبات النظام


الكلمة الأساسية للقراءة فقط مختلفة عن الكلمة الأساسية const . لا يمكن تهيئة حقل const إلا في إعلان الحقل. يمكن تهيئة حقل readonly إما في التعريف أو في مُنشئ . لذلك ، يمكن أن تحتوي الحقول للقراءة فقط على قيم مختلفة بناءً على المُنشئ المستخدم. أيضاً ، بينما حقل const ثابت ثابت وقت ، يمكن استخدام الحقل readonly لثوابت وقت التشغيل كما في المثال التالي:

public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;

الكلمة الأساسية للقراءة فقط مختلفة عن الكلمة الأساسية const. لا يمكن تهيئة حقل const إلا في إعلان الحقل. يمكن تهيئة حقل readonly إما في التعريف أو في مُنشئ. لذلك ، يمكن أن تحتوي الحقول للقراءة فقط على قيم مختلفة بناءً على المُنشئ المستخدم. أيضاً ، بينما حقل const ثابت ثابت وقت ، يمكن استخدام الحقل readonly لثوابت وقت التشغيل كما في المثال التالي:

public static readonly uint l1 = (uint) DateTime.Now.Ticks;


تتشابه Const و readonly ، ولكنها ليست متطابقة تمامًا. الحقل const هو ثابت وقت تجميع ، مما يعني أنه يمكن حساب هذه القيمة في وقت التحويل البرمجي. يمكّن حقل readonly سيناريوهات إضافية يجب تشغيل بعض التعليمات البرمجية أثناء إنشاء النوع. بعد البناء ، لا يمكن تغيير حقل للقراءة فقط.

على سبيل المثال ، يمكن استخدام أعضاء Const لتحديد أعضاء مثل:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

لأن القيم مثل 3.14 و 0 هي ثوابت وقت التحويل البرمجي. ومع ذلك ، ضع في اعتبارك الحالة التي تحدد فيها نوعًا ما وتريد تقديم بعض الأمثلة المسبقة عنه. على سبيل المثال ، قد ترغب في تحديد فئة اللون وتوفير "ثوابت" للألوان الشائعة مثل الأسود والأبيض ، وما إلى ذلك. ليس من الممكن القيام بذلك مع أعضاء Const ، حيث أن جوانب اليد اليمنى ليست ثوابت وقت التحويل البرمجي. يمكن للمرء أن يفعل ذلك مع أعضاء ثابت منتظم:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

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

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

من المثير للاهتمام ملاحظة أن أعضاء Const ثابتون دائمًا ، في حين أن العضو القابل للقراءة يمكن أن يكون إما ثابتًا أو لا ، تمامًا مثل الحقل العادي.

من الممكن استخدام كلمة أساسية واحدة لهذين الغرضين ، ولكن هذا يؤدي إلى مشاكل في الإصدار أو مشاكل في الأداء. لنفترض للحظة أننا استخدمنا كلمة رئيسية واحدة لهذا (const) وكتب مطوّر برامج:

public class A
{
    public static const C = 0;
}

وكتب مطور مختلف التعليمات البرمجية التي تعتمد على A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

الآن ، هل يمكن أن يعتمد التعليمة البرمجية التي تم إنشاؤها على حقيقة أن AC هو ثابت وقت التجميع؟ أي ، هل يمكن استبدال التيار المتردد ببساطة بالقيمة 0؟ إذا قلت "نعم" لهذا ، فهذا يعني أن مطور A لا يمكنه تغيير طريقة تهيئة AC - وهذا يربط بين يدي المطور A بدون إذن. إذا قلت "لا" لهذا السؤال ، فحينئذٍ يتم تفويت عملية تحسين مهمة. ربما يكون مؤلف A هو إيجابي بأن AC سيظل صفرًا دائمًا. يسمح استخدام كل من const و readonly لمطوّر A بتحديد الهدف. هذا يجعل لسلوك إصدار أفضل وكذلك أداء أفضل.


شيء واحد أن أضيف إلى ما قاله الناس أعلاه. إذا كان لديك تجميع يحتوي على قيمة للقراءة فقط (على سبيل المثال ، للقراءة فقط MaxFooCount = 4؛) ، يمكنك تغيير القيمة التي تراها استدعاء التجميع عن طريق شحن إصدار جديد من ذلك التجميع بقيمة مختلفة (على سبيل المثال ، للقراءة فقط MaxFooCount = 5؛)

ولكن مع const ، سيتم طيها في رمز المتصل عند تجميع المتصل.

إذا وصلت إلى هذا المستوى من إجادة C # ، فأنت جاهز لكتاب Bill Wagner ، Effective C #: 50 طرق محددة لتحسين C # التي تجيب على هذا السؤال بالتفصيل (و 49 أشياء أخرى).


فقط لإضافة ، ReadOnly لأنواع المرجعية فقط يجعل المرجع للقراءة فقط وليس القيم. فمثلا:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

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

مثال:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}

لا يمكن تهيئة حقل const إلا في إعلان الحقل. يمكن تهيئة حقل readonly إما في التعريف أو في مُنشئ.


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


وبصرف النظر عن الاختلاف الظاهري لل

  • الاضطرار إلى تعريف القيمة في وقت تعريف من أجل قيم readonly VS const يمكن حسابها بشكل حيوي ولكن تحتاج إلى تعيين قبل أن يتم إنهاء منشئ .. بعد أن يتم تجميدها.
  • "const's static ضمنيًا. يمكنك استخدام منهج ClassName.ConstantName للوصول إليها.

هناك فرق دقيق. النظر في فئة محددة في AssemblyA .

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

تشير AssemblyA ويستخدم هذه القيم في التعليمات البرمجية. عندما يتم تجميع هذا ،

  • في حالة قيمة const ، يشبه البحث عن استبدال ، يتم "القيمة المخزنة في" القيمة 2 في IL الخاص بـ AssemblyB . وهذا يعني أنه إذا كان غدًا I_CONST_VALUE إلى 20 في المستقبل. سيكون لدى AssemblyB 2 حتى يعيد ذلك .
  • في حالة القيمة readonly ، فهو يشبه ref إلى موقع ذاكرة. لا يتم خبز القيمة إلى IL في AssemblyB . هذا يعني أنه إذا تم تحديث موقع الذاكرة ، يحصل AssemblyB على القيمة الجديدة بدون إعادة التوليف. لذلك إذا تم تحديث I_RO_VALUE إلى 30 ، فستحتاج فقط إلى إنشاء AssemblyA . جميع العملاء لا يحتاجون إلى إعادة تجميع.

لذا إذا كنت واثقًا من أن قيمة الثابت لن تتغير ، فاستخدم ثوابت.

public const int CM_IN_A_METER = 100;

ولكن إذا كان لديك ثابت قد يتغير (دقة egwrt) .. أو عندما تكون في شك ، استخدم readonly .

public readonly float PI = 3.14;

تحديث: يحتاج Aku للحصول على ذكر coz أشار إلى هذا أولاً. أيضا أحتاج إلى سد حيث تعلمت هذا .. فعال C # - بيل فاغنر


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

public class MyClass
{
    public const double PI1 = 3.14159;
}

يشبه العضو readonly ثابت في أنه يمثل قيمة ثابتة. الفرق هو أنه يمكن تهيئة عضو readonly في وقت التشغيل ، منشئ ، بالإضافة إلى إمكانية التهيئة كما تم الإعلان عنها.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

CONST

  • لا يمكن اعتبارها static (فهي ضمنية ثابتة)
  • يتم تقييم قيمة الثابت في وقت التحويل البرمجي
  • تتم تهيئة الثوابت عند الإعلان فقط

يقرأ فقط

  • يمكن أن تكون إما مستوى مثيل أو ثابت
  • يتم تقييم القيمة في وقت التشغيل
  • يمكن تهيئة readonly في تعريف أو بواسطة التعليمات البرمجية في المنشئ

يجب أن يكون الثابت الثابت مشفرًا ، حيث يمكن تعيين readonly في مُنشئ الفصل.


هذا ما يفسر ذلك . ملخص: يجب تهيئة const في وقت تعريف ، يمكن تهيئة readonly على المنشئ (وبالتالي قيمة مختلفة اعتماداً على المنشئ المستخدم).

تحرير: انظر غيشو في gotcha أعلاه للاختلاف الدقيق


إليك رابط آخر يوضح كيف أن الإصدار الثابت ليس إصدارًا آمنًا أو ملائمًا لأنواع المراجع.

ملخص :

  • يتم تعيين قيمة الخاصية const في وقت التحويل البرمجي ولا يمكن تغييرها في وقت التشغيل
  • لا يمكن وضع علامة ثابتة على Const: تشير الكلمة الأساسية إلى أنها ثابتة ، على عكس الحقول التي يمكن قراءتها.
  • Const لا يمكن أن يكون أي شيء عدا أنواع القيمة (البدائية)
  • تشير الكلمة الأساسية للقراءة فقط إلى الحقل على أنه غير قابل للتغيير. ومع ذلك ، يمكن تغيير الخاصية داخل مُنشئ الفصل
  • يمكن أيضاً دمج الكلمة الأساسية للقراءة فقط مع الثابت لجعلها تعمل بنفس الطريقة مثل const (على الأقل على السطح). هناك فرق واضح عندما تنظر إلى IL بين الاثنين
  • يتم وضع علامة على حقول const كـ "حرفية" في IL أثناء readonly "initonly"

مسكتك آخر.

نظرًا لأن const لا يعمل إلا مع أنواع البيانات الأساسية ، إذا كنت ترغب في العمل مع فصل دراسي ، قد تشعر "بالقوة" لاستخدام ReadOnly. ومع ذلك ، حذار من الفخ! يعني ReadOnly أنه لا يمكنك استبدال الكائن بكائن آخر (لا يمكنك جعله يشير إلى كائن آخر). ولكن أي عملية تحتوي على مرجع إلى الكائن تكون مجانية لتعديل القيم داخل الكائن!

لذلك لا ينبغي أن نخلط في التفكير في أن ReadOnly تعني أن المستخدم لا يمكنه تغيير الأشياء. لا توجد بنية بسيطة في C # لمنع إنشاء مثيل لفئة من تغيير قيمها الداخلية (بقدر ما أعرف).


ثابت

نحن بحاجة إلى توفير القيمة إلى الحقل const عندما يتم تعريفها. يحفظ المحول البرمجي بعد ذلك قيمة الثابت في بيانات التعريف الخاصة بالتجميع. هذا يعني أنه يمكن تحديد ثابت فقط للنوع البدائي مثل boolean ، char ، byte وما إلى ذلك. دائمًا ما تعتبر الثوابت أعضاء ثابتين ، وليس أعضاء نسخة.

يقرأ فقط

يمكن فقط حل الحقول للقراءة فقط في وقت التشغيل. وهذا يعني أنه يمكننا تحديد قيمة لقيمة باستخدام المُنشئ للنوع الذي يتم فيه الإعلان عن الحقل. يتم إجراء التحقق بواسطة المحول البرمجي الذي لا تتم كتابة الحقول readonly إلى بواسطة أي أسلوب آخر غير منشئ.

المزيد عن كليهما الموضحة هنا في هذا المقال







readonly