الكلمات المفتاحية 'readonly' و 'const'
جزء من قسم Object Oriented Programming في رحلة C# على Coddy — الدرس 16 من 70.
توفر لغة C# كلمتين رئيسيتين لإنشاء قيم لا يمكن تغييرها: const و readonly. بينما يمنع كلاهما التعديل، إلا أنهما يعملان بشكل مختلف ويخدمان أغراضاً متميزة.
يجب تعيين قيمة للحقل const عند التصريح عنه، ويتم تحديد قيمته في وقت التجميع (compile time). إنه ثابت (static) بشكل ضمني، مما يعني أنه ينتمي إلى الفئة (class) بدلاً من الكائنات (instances):
public class GameSettings
{
public const int MaxPlayers = 4;
public const double Gravity = 9.81;
}يمكنك الوصول إلى الثوابت من خلال اسم الفئة: GameSettings.MaxPlayers. تعمل الثوابت فقط مع الأنواع الأولية، والسلاسل النصية، و null لأن المترجم يجب أن يعرف القيمة الدقيقة.
يمكن تعيين حقل readonly عند التصريح عنه أو في المنشئ (constructor)، ويتم تحديد قيمته في وقت التشغيل (runtime):
public class Player
{
public readonly string Id;
public readonly DateTime CreatedAt = DateTime.Now;
public Player(string id)
{
Id = id;
}
}على عكس const، يمكن لحقول readonly أن تحمل أي نوع ويمكن أن يكون لها قيم مختلفة لكل مثيل. بمجرد انتهاء المنشئ (constructor)، لا يمكن تغيير القيمة.
استخدم const للقيم العالمية حقًا والتي لن تتغير أبدًا، مثل الثوابت الرياضية. استخدم readonly للقيم التي يجب تعيينها مرة واحدة ولكنها قد تختلف بين الكائنات أو تحتاج إلى حساب وقت التشغيل.
التحدي
سهللنقم ببناء نظام تكوين لمحاكاة فيزيائية يوضح متى يتم استخدام const للثوابت العالمية مقابل readonly للقيم التي يتم تعيينها مرة واحدة عند وقت التشغيل.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
PhysicsConstants.cs: قم بتعريف فئةPhysicsConstantsداخل مساحة الأسماءSimulation. يجب أن تحتوي هذه الفئة على ثوابت عالمية لا تتغير أبداً وهي نفسها في كل مكان:- حقل
constباسمGravityوقيمته9.81 - حقل
constباسمSpeedOfLightوقيمته299792458 - حقل
constنصي (string) باسمGravityUnitوقيمته"m/s^2"
- حقل
Projectile.cs: قم بتعريف فئةProjectileداخل مساحة الأسماءSimulation. كل قذيفة لها قيم يجب تعيينها مرة واحدة عند إنشائها ولا يتم تعديلها بعد ذلك أبداً:- حقل
readonlyباسمName(string) - حقل
readonlyباسمInitialVelocity(double) - حقل
readonlyباسمLaunchAngle(double، بالدرجات) - منشئ (constructor) يقبل ويقوم بتعيين القيم الثلاث جميعاً
- دالة
GetMaxHeight()تقوم بحساب أقصى ارتفاع باستخدام الصيغة:(velocity^2 * sin^2(angle)) / (2 * gravity). استخدمMath.Sin()وقم بتحويل الدرجات إلى راديان عن طريق الضرب فيMath.PI / 180
- حقل
Program.cs: في ملفك الرئيسي، قم بإنشاء قذيفة باستخدام قيم الإدخال واعرض الثوابت الفيزيائية جنباً إلى جنب مع أقصى ارتفاع محسوب للقذيفة.
ستتلقى ثلاثة مدخلات:
- اسم القذيفة (Projectile name)
- السرعة الابتدائية (Initial velocity) (بالمتر/ثانية)
- زاوية الإطلاق (Launch angle) (بالدرجات)
اطبع المخرجات بهذا التنسيق:
Gravity: {Gravity} {GravityUnit}
Speed of Light: {SpeedOfLight} m/s
Projectile: {Name}
Initial Velocity: {InitialVelocity} m/s
Launch Angle: {LaunchAngle} degrees
Max Height: {maxHeight} mقم بتقريب أقصى ارتفاع إلى منزلتين عشريتين باستخدام Math.Round(value, 2).
على سبيل المثال، إذا كانت المدخلات هي Rocket، و 50، و 45، يجب أن تكون المخرجات:
Gravity: 9.81 m/s^2
Speed of Light: 299792458 m/s
Projectile: Rocket
Initial Velocity: 50 m/s
Launch Angle: 45 degrees
Max Height: 63.71 mورقة مرجعية
توفر لغة C# كلمتين رئيسيتين لإنشاء قيم غير قابلة للتغيير (immutable): const و readonly.
يجب تعيين قيمة للحقل const عند التصريح عنه، ويتم تحديد قيمته في وقت التجميع (compile time)، ويكون ثابتًا بشكل ضمني (implicitly static):
public class GameSettings
{
public const int MaxPlayers = 4;
public const double Gravity = 9.81;
}يتم الوصول إلى الثوابت من خلال اسم الفئة: GameSettings.MaxPlayers. تعمل الثوابت فقط مع الأنواع الأولية (primitive types)، والسلاسل النصية (strings)، والقيمة null.
يمكن تعيين قيمة للحقل readonly عند التصريح عنه أو داخل المشيد (constructor)، ويتم تحديد قيمته في وقت التشغيل (runtime):
public class Player
{
public readonly string Id;
public readonly DateTime CreatedAt = DateTime.Now;
public Player(string id)
{
Id = id;
}
}يمكن لحقول readonly أن تحمل أي نوع ويمكن أن يكون لها قيم مختلفة لكل كائن (instance). بمجرد انتهاء المشيد، لا يمكن تغيير القيمة.
استخدم const للقيم العالمية التي لن تتغير أبدًا. واستخدم readonly للقيم التي يجب تعيينها مرة واحدة ولكنها قد تختلف بين الكائنات أو تحتاج إلى حساب في وقت التشغيل.
جرّب بنفسك
using System;
using Simulation;
class Program
{
public static void Main(string[] args)
{
// قراءة المدخلات
string name = Console.ReadLine();
double velocity = Convert.ToDouble(Console.ReadLine());
double angle = Convert.ToDouble(Console.ReadLine());
// TODO: إنشاء كائن `Projectile` باستخدام قيم المدخلات
// TODO: طباعة الثوابت الفيزيائية (Gravity مع الوحدة، Speed of Light)
// TODO: طباعة معلومات المقذوف (Name، Initial Velocity، Launch Angle)
// TODO: حساب وطباعة أقصى ارتفاع (مقرباً إلى منزلتين عشريتين)
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةNamespaces والتوجيهاتمقدمة في Classes و Objectsالكلمة المفتاحية 'this'Methods والمعاملاتFields مقابل PropertiesConstructorsObject Initializersمراجعة - آلة حاسبة بسيطة4الوراثة
صيغة الوراثة الأساسية (:)الكلمة المفتاحية 'base'الكلمات المفتاحية Virtual و Overrideالأصناف المختومة (Sealed Classes)الفئة الأساسية 'object'مراجعة - هيكلية الموظفين7ميزات متقدمة
تحميل العوامل (Operator Overloading)المفهرسات (Indexers (this[]))إعادة تعريف ()ToStringدوال التوسعة (Extension Methods)ملخص - Custom List2الخصائص والأعضاء الساكنة (Static Members)
الخصائص المطبقة تلقائيًا (Auto-Implemented Properties)خصائص القراءة فقط والكتابة فقطالحقول والدوال الساكنة (Static)الفئات الساكنة (Static Classes)الأعضاء ذات البنية التعبيرية (Expression-Bodied Members)5تعدد الأشكال والواجهات (Polymorphism & Interfaces)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالواجهة مقابل الفئة المجردة (Abstract Class)الواجهات المتعددةالواجهات الصريحةUpcasting و Downcastingملخص - حاسبة الأشكال8مفاهيم البرمجة كائنية التوجه (OOP) المتقدمة
التركيب بدلاً من الوراثةالـ Generics (الأصناف والدوال)الـ Delegates والأحداثالـ Attributes والـ Reflectionواجهة IDisposable وجملة usingأساسيات Dependency Injection3بنية الكلاسات
بيانات الـ Instance مقابل البيانات الـ Staticالكلمات المفتاحية 'readonly' و 'const'الحقول الخلفية (Backing Fields)مراجعة - مدير الحساب البنكي