مقدمه
در برنامهنویسی، اغلب با مقادیری سروکار داریم که پس از مقداردهی اولیه، نباید هرگز تغییر کنند.
ایجاد دادههای تغییرناپذیر (Immutable) یک اصل مهم در طراحی نرمافزار است که به
افزایش پیشبینیپذیری، امنیت و سادگی کد، به خصوص در برنامههای چندنخی (multi-threaded) کمک
میکند. زبان C# دو کلمهی کلیدی اصلی برای این منظور فراهم میکند: const و readonly. هرچند هر دو برای
ایجاد مقادیر ثابت به کار میروند، اما تفاوتهای بسیار مهمی در زمان مقداردهی و نحوهی عملکردشان
دارند که درک آنها برای هر برنامهنویس C# ضروری است.
ثابتها با کلمهی کلیدی const
یک ثابت const، فیلدی است که مقدار آن در زمان کامپایل
(compile-time) مشخص و ثابت میشود. این یعنی کامپایلر مقدار آن را مستقیماً در کد
جایگزین میکند.
ویژگیهای ثابتهای const
- مقداردهی در زمان تعریف: یک فیلد const
حتماً باید در همان خطی که تعریف میشود، مقداردهی شود.
- مقدار ثابت در زمان کامپایل: مقداری که به یک const اختصاص داده میشود، باید برای کامپایلر مشخص باشد. این
مقدار میتواند یک لیترال (مانند عدد یا رشته) یا یک عبارت متشکل از ثابتهای دیگر باشد. شما
نمیتوانید نتیجهی یک متد یا یک شیء جدید را به آن اختصاص دهید.
- ذاتاً استاتیک: فیلدهای const به طور ضمنی static هستند. آنها به کلاس تعلق دارند، نه به یک نمونهی خاص.
بنابراین، برای دسترسی به آنها از نام کلاس استفاده میکنیم.
Program.cs
public class MathConstants
{
public const double PI = 3.14159;
public const string AppVersion = "2.1.0";
}
Console.WriteLine($"Value of PI: {MathConstants.PI}");
در مثال بالا، PI و AppVersion مقادیر ثابتی هستند که در زمان کامپایل مشخصاند و
هرگز تغییر
نخواهند کرد.
فیلدهای فقط-خواندنی با کلمهی کلیدی readonly
یک فیلد فقط-خواندنی readonly، فیلدی است که مقدار آن در زمان
اجرا (run-time) و در لحظهی ایجاد شیء، ثابت میشود. این تفاوت اصلی آن با
const
است.
ویژگیهای فیلدهای readonly
- مقداردهی در زمان تعریف یا در سازنده: یک فیلد readonly میتواند یا در
زمان
تعریف مقداردهی شود، یا مقدار آن در سازنده (constructor) کلاس تعیین گردد. پس
از خروج از سازنده، مقدار آن دیگر قابل تغییر نیست.
- مقدار متغیر در زمان اجرا: از آنجایی که مقداردهی در زمان اجرا انجام میشود،
میتوان هر مقدار معتبری را به آن اختصاص داد، از جمله نتیجهی فراخوانی یک متد یا یک شیء جدید.
- میتواند نمونه یا استاتیک باشد: برخلاف const، یک فیلد
readonly میتواند
هم به عنوان عضو نمونه (که برای هر شیء مقدار متفاوتی دارد) و هم به عنوان عضو استاتیک
(static readonly) تعریف شود.
Program.cs
public class User
{
public readonly Guid UserId;
public string Username;
public User(string username)
{
UserId = Guid.NewGuid();
Username = username;
}
public void ChangeId()
{
}
}
در این مثال، UserId برای هر کاربر یک شناسهی یکتاست که در زمان ساخت کاربر ایجاد و تنظیم
میشود. پس از آن، این شناسه برای تمام طول عمر شیء User ثابت باقی میماند. هر نمونهی
User
مقدار UserId متفاوتی خواهد داشت.
مقایسهی دقیق const و readonly
برای درک کامل، بهتر است این دو کلمهی کلیدی را مستقیماً با هم مقایسه کنیم.
ویژگی |
`const` |
`readonly` |
زمان مقداردهی |
زمان کامپایل |
زمان اجرا (در سازنده یا زمان تعریف) |
مقدار مجاز |
باید ثابت زمان کامپایل باشد (لیترالها) |
میتواند هر عبارت معتبری باشد (نتیجه متد و ...) |
ماهیت |
همیشه استاتیک (static) |
میتواند استاتیک یا نمونه (instance) باشد |
انواع داده مجاز |
فقط انواع دادهی پایهای و string |
هر نوع دادهای (کلاس، ساختار و ...) |
چه زمانی از کدامیک استفاده کنیم؟
- از const استفاده کنید برای ثابتهای واقعی و
گلوبال که مقدار آنها هرگز در هیچ شرایطی تغییر نمیکند. مانند ثابتهای ریاضی
(Math.PI) یا مقادیر رشتهای که در کل برنامه ثابت هستند.
- از readonly استفاده کنید برای مقادیری که به یک نمونهی
خاص از کلاس وابستهاند و پس از ایجاد آن شیء نباید تغییر کنند. مانند شناسهی
یکتا یا تاریخ ایجاد یک رکورد.
- از static readonly استفاده کنید برای مقادیر ثابتی که در
زمان کامپایل مشخص نیستند و باید در زمان اجرا محاسبه یا بارگذاری شوند، اما پس از
آن در کل برنامه ثابت باقی میمانند. مانند یک شیء تنظیمات که از یک فایل خوانده میشود.
Program.cs
public class Configuration
{
public static readonly int Timeout;
static Configuration()
{
Timeout = 30;
}
}
در این مثال، مقدار Timeout ممکن است از یک فایل خارجی خوانده شود، بنابراین نمیتواند
const
باشد. اما چون پس از بارگذاری نباید تغییر کند، static readonly بهترین انتخاب است.