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

ประโยชน์ของการใช้ readonly กับ Field ใน C#

readonly เป็น Modifier สำหรับ Field (Field Declaration) ที่บ่งบอกว่า Field นี้สามารถกำหนดค่าได้เฉพาะ:

  1. ตอนประกาศ (Declaration)
  2. ใน Constructor ของคลาสเดียวกัน (Instance Constructor หรือ Static Constructor)

ต่างจาก const ที่ต้องเป็น Compile-time Constant และเป็น Static โดยอัตโนมัติ

4 Contexts ของ readonly

Context Syntax คำอธิบาย
Field Declaration readonly int _maxSize = 100; Instance หรือ Static Field
Readonly Struct readonly struct Point { ... } Struct ทั้งหมด Immutable (C# 7.2+)
Readonly Member readonly void Method() / readonly int Prop => _field; Method/Property ไม่ Mutate State (C# 8.0+)
Ref Readonly Return ref readonly int GetRef() Return Ref แต่ไม่อนุญาตให้แก้ไข (C# 7.2+)

ตัวอย่าง: readonly Field

public class Configuration
{
    // 1. Init ที่ Declaration
    private readonly string _appName = "MyApp";
    
    // 2. Init ใน Constructor (Runtime Value)
    private readonly string _connectionString;
    private readonly DateTime _createdAt;
    
    public Configuration(string connStr)
    {
        _connectionString = connStr;        // OK
        _createdAt = DateTime.UtcNow;       // OK - Runtime Value
        // _appName = "New";                // ❌ Compile Error: Readonly
    }
    
    // Readonly Property (Expression-bodied)
    public string ConnectionString => _connectionString; // Readonly by nature
    public DateTime CreatedAt => _createdAt;
}

ตัวอย่าง: readonly Struct (C# 7.2+)

// Struct ทั้งชิ้น Immutable - ป้องกัน Accidental Mutation
public readonly struct Point3D
{
    public readonly double X; // Field ต้อง readonly ด้วย
    public readonly double Y;
    public readonly double Z;
    
    public Point3D(double x, double y, double z)
    {
        X = x; Y = y; Z = z;
    }
    
    // Method ต้องเป็น readonly ด้วย (ไม่สามารถ Mutate ได้)
    public readonly double DistanceFromOrigin() => Math.Sqrt(X*X + Y*Y + Z*Z);
    
    // Property ได้ปกติ (แต่ไม่ควรมี Setter)
    public double Magnitude => DistanceFromOrigin();
}

ตัวอย่าง: readonly Member (C# 8.0+)

public class Counter
{
    private int _count;
    
    // Method นี้รับประกันว่าไม่ Mutate State
    public readonly int GetCount() => _count;
    
    // Property แบบ Readonly
    public readonly int Count => _count;
    
    // Method ที่ Mutate - ไม่สามารถเป็น readonly
    public void Increment() => _count++;
}

ตัวอย่าง: ref readonly Return (C# 7.2+)

public class LargeStructContainer
{
    private readonly LargeStruct _data = new LargeStruct(); // สมมติใหญ่
    
    // คืน Reference แต่ไม่อนุญาตให้แก้ไข (Performance: No Copy)
    public ref readonly LargeStruct GetData() => ref _data;
}

// ใช้งาน
var container = new LargeStructContainer();
ref readonly var data = ref container.GetData();
// data.SomeField = 10; // ❌ Compile Error: Cannot assign to readonly variable
var copy = data; // OK: Copy ค่าไป (ถ้าต้องการแก้)

ประโยชน์หลัก

  • Immutability Guarantee: Compiler Enforce ไม่ให้เปลี่ยนค่าหลัง Constructor
  • Thread Safety: Read-only Data ปลอดภัยต่อ Thread โดยธรรมชาติ
  • Intent Clarity: บอก Maintainer ว่า Field นี้ "Set Once"
  • Compiler Optimizations: JIT อาจ Optimize ได้ดีขึ้น (Constant Propagation)
  • Defensive Copy Prevention: ref readonly หลีกเลี่ยง Copy Struct ใหญ่

readonly vs const

Feature const readonly
Value Set Compile-time Runtime (Constructor)
Static Implicit Static Instance หรือ Static
Type Primitive/String/Enum/Null only Any Type
Versioning Burn into Caller IL (Breaking Change) Runtime Lookup (Safe)

Best Practice

  • ใช้ readonly เป็น Default สำหรับ Fields ที่ไม่ควรเปลี่ยนหลัง Init
  • ใช้ readonly struct สำหรับ Immutable Value Types
  • ใช้ readonly Methods/Properties เพื่อ Document Intent
  • หลีกเลี่ยง const สำหรับค่าที่อาจเปลี่ยน (Version, Config, Connection String)