Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

ความแตกต่างระหว่าง const และ readonly ใน C#

const vs readonly ใน C#

ทั้งคู่ใช้สำหรับค่าที่ **ไม่เปลี่ยนแปลง** (immutable) หลังจากกำหนด แต่มีขอบเขตและเวลาที่กำหนดค่าแตกต่างกัน

const (Constant) - ค่าคงที่ในเวลาคอมไพล์

  • ต้องกำหนดค่า **ตอนประกาศ** (compile-time constant)
  • เป็น static โดยอัตโนมัติ (ไม่ต้องเขียน static)
  • ค่าต้องเป็น compile-time constant (literal, const อื่น, หรือ expression ที่คำนวณได้ตอน compile)
  • ไม่สามารถเปลี่ยนค่าได้เด็ดขาด
  • เหมาะสำหรับค่าที่ไม่มีวันเปลี่ยน: PI, จำนวนวันในสัปดาห์, App name

class Constants
{
    public const double PI = 3.14159265359;
    public const int DaysInWeek = 7;
    public const string AppName = "MyApp";
    
    // ❌ ไม่ได้: const int x = SomeMethod(); // ต้องเป็น compile-time
    // ❌ ไม่ได้: const DateTime Now = DateTime.Now; // ไม่ใช่ constant
}

readonly - ค่าคงที่ในเวลารันไทม์

  • กำหนดค่าได้ **ตอนประกาศ** หรือ **ใน Constructor** เท่านั้น
  • สามารถเป็น **instance member** (แต่ละ instance ค่าต่างกันได้) หรือ static readonly
  • ค่าสามารถมาจาก runtime calculation, config, database, dependency injection
  • เหมาะสำหรับค่าที่ตั้งค่าตอนรัน: connection string, config, injected services

class Settings
{
    // Instance readonly - ตัวแต่ละ instance ค่าต่างกันได้
    public readonly string ConnectionString;
    public readonly int MaxRetries;
    
    // Static readonly - ค่าร่วมกันทุก instance
    public static readonly DateTime StartupTime = DateTime.Now;
    
    public Settings(string connStr, int retries = 3)
    {
        ConnectionString = connStr; // กำหนดใน constructor
        MaxRetries = retries;
    }
    
    // ✅ สามารถใช้ method/property ในการคำนวณ
    public readonly int Timeout = GetDefaultTimeout(); 
    
    static int GetDefaultTimeout() => 30;
}

ตารางเปรียบเทียบ

คุณสมบัติconstreadonly
เวลากำหนดค่าCompile-timeRuntime (declaration หรือ constructor)
Static/InstanceStatic เท่านั้น (implicit)Static หรือ Instance ได้
ชนิดข้อมูลที่อนุญาตPrimitive, string, enum, null, reference type (เฉพาะ null)ทุกชนิด (class, struct, array, etc.)
การเข้าถึงClassName.CONST_NAMEinstance.ReadonlyField หรือ ClassName.StaticReadonly
Versioning (DLL)ค่า embed ใน calling assemblyอ่านจาก defining assembly รันไทม์
Performanceเร็วกว่าเล็กน้อย (inline)เข้าถึง field ปกติ

Versioning Issue - สำคัญ!


// Assembly A (Library)
public class Config
{
    public const int MaxConnections = 100; // Compile-time
    public static readonly int DefaultTimeout = 30; // Runtime
}

// Assembly B (Consumer) - ใช้ Config
// ถ้า Assembly A เปลี่ยน MaxConnections = 200 และ rebuild แค่ A
// Assembly B ยังคงเห็น 100 (เพราะ embed ตอน compile B)
// แต่ DefaultTimeout จะเห็น 30 ใหม่ (อ่าน runtime)

แนวทางเลือกใช้


// ใช้ const เมื่อ:
// - ค่าเป็นค่าคงที่จริง ไม่มีวันเปลี่ยน
// - เป็น primitive/string/enum
// - ต้องการ performance เล็กน้อย
public const int MaxBufferSize = 4096;

// ใช้ readonly เมื่อ:
// - ค่ามาจาก config, DI, runtime calculation
// - เป็น reference type (array, object, List)
// - ต้องการ instance-specific values
// - อาจเปลี่ยนใน version ถัดไป (versioning safety)
public readonly string[] AllowedOrigins;
public readonly ILogger Logger;

public MyClass(IConfiguration config, ILogger logger)
{
    AllowedOrigins = config.GetSection("Cors:Origins").Get();
    Logger = logger;
}

C# 11: required keyword


class Config
{
    public required string ConnectionString { get; init; } // ต้อง set ตอนสร้าง object
    public required int Port { get; init; }
}

// ใช้งาน - compile error ถ้าไม่ set
var cfg = new Config { ConnectionString = "...", Port = 5432 };