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

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

ความแตกต่างหลัก

คุณสมบัติconstreadonly
Evaluation TimeCompile-time ConstantRuntime Constant
Value Assignmentต้อง Assign ตอน DeclarationAssign ได้ใน Declaration หรือ Constructor
Modifiableไม่สามารถเปลี่ยนได้เลยเปลี่ยนได้ใน Constructor (Instance)
ScopeImplicitly StaticInstance หรือ Static
Type RestrictionsBuilt-in Types, String, Enum, NullAny Type (Class, Struct, Array, etc.)
In Methodได้ (Local Constant)ไม่ได้ (Field Only)
Versioningค่า Embedded ใน Caller Assemblyอ่านจาก Assembly ตอน Runtime

const - Compile-time Constant


public class Constants
{
    // ต้องเป็น Constant Expression (Compile-time Known)
    public const double PI = 3.14159265359;
    public const int MaxRetries = 3;
    public const string AppName = "MyApp";
    
    // ❌ Error: Not a constant expression
    // public const DateTime BuildDate = DateTime.Now;
    // public const List Numbers = new List { 1, 2 };
}

// Usage - ค่าถูก Inline เข้า Caller IL
void Test()
{
    Console.WriteLine(Constants.PI); // IL: ldc.r8 3.14159...
}

readonly - Runtime Constant


public class Config
{
    // Instance Readonly - Assign ใน Constructor
    public readonly string ConnectionString;
    public readonly int MaxConnections;
    public readonly List AllowedHosts;
    
    public Config(string env)
    {
        // Runtime Logic ได้
        ConnectionString = LoadFromConfig(env);
        MaxConnections = env == "Prod" ? 100 : 10;
        AllowedHosts = LoadHostsFromDb(); // Complex Logic
    }
    
    // Static Readonly - Assign ใน Static Constructor
    public static readonly string Version;
    
    static Config()
    {
        Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
    }
}

Versioning Issue (สำคัญมาก!)

⚠️ const = Versioning Problem
Library v1: public const int Max = 100;
App Compile → IL: ldc.i4.s 100 (ค่าถูก Burn ใน App)
Library v2: public const int Max = 200;
App Re-run ไม่ Recompile → ยังใช้ 100!

readonly = Safe
Library v1: public static readonly int Max = 100;
App Run → อ่านค่าจาก Library DLL ตอน Runtime → ได้ 200 เมื่อ Update DLL

ตัวอย่าง Versioning


// Library.dll v1
public class Settings
{
    public const int ConstMax = 100;
    public static readonly int ReadonlyMax = 100;
}

// App.exe references Library.dll
class Program
{
    static void Main()
    {
        Console.WriteLine(Settings.ConstMax);    // 100 (Burned in App IL)
        Console.WriteLine(Settings.ReadonlyMax); // 100 (Read from Library)
    }
}

// Update Library.dll v2 (ไม่ Recompile App)
// ConstMax = 200, ReadonlyMax = 200

// Run App.exe อีกครั้ง:
// ConstMax: 100 (เก่า!)
// ReadonlyMax: 200 (ใหม่!)

Local Constants (ใน Method)


void Calculate()
{
    const double TaxRate = 0.07; // Local Const - OK
    // readonly double Rate = 0.07; // ❌ Error: readonly not valid on local
    
    const int BufferSize = 4096;
    // ...
}

Best Practice

  • ✅ const: ค่าคงที่จริง (Math Constants, Enum-like, Protocol Values) ที่ไม่เปลี่ยนแปลงตลอดกาล
  • ✅ readonly: Configuration, Settings, Injected Dependencies, Complex Objects, ค่าที่อาจเปลี่ยน Version
  • ✅ static readonly: Singleton, Shared Configuration, Expensive Initialization
  • ✅ ใช้ const สำหรับ default Parameter Values
  • ❌ อย่าใช้ const สำหรับ Version Numbers, Feature Flags, Config Values

Modern Alternative: init-only Properties (C# 9+)


public class Settings
{
    // Immutable after construction, รองรับ Object Initializer
    public int MaxConnections { get; init; } = 100;
    public string ConnectionString { get; init; } = "";
    
    // Required (C# 11+)
    public required string ApiKey { get; init; }
}