คำตอบ: ใช้ readonly Keyword
C# ไม่มีคีย์เวิร์ด final เหมือน Java แทนนั้นใช้ readonly สำหรับ Field/Variable ที่ต้องการให้กำหนดค่าได้ครั้งเดียว (ระหว่าง Declaration หรือใน Constructor)
readonly vs const
| คุณสมบัติ | const |
readonly |
|---|---|---|
| กำหนดค่าเมื่อไหร่ | Compile Time (ตอนประกาศ) | Runtime (ใน Constructor) |
| Static โดยค่าเริ่มต้น | ใช่ (Implicit Static) | ไม่ใช่ (Instance หรือ Static ได้) |
| Type ที่รองรับ | Primitive Types, String, Enum, Null | ทุก Type (Reference Types รวม) |
| การใช้งาน | Constant Values (Pi, MaxSize) | Runtime Constants, DI, Configuration |
| Memory | แทนค่าตรงโค้ด (Constant Folding) | Field จริงใน Object |
ตัวอย่าง readonly Field
public class Department {
// readonly Field - กำหนดค่าได้ครั้งเดียว
private readonly int _employeeCount;
// Constructor - ที่นี่กำหนดค่า readonly ได้
public Department(int employeeCount) {
_employeeCount = employeeCount; // OK
}
public void ChangeCount() {
// _employeeCount = 150; // ❌ Compile Error: A readonly field cannot be assigned to
}
public int GetEmployeeCount() => _employeeCount;
}
readonly กับ Reference Types
สำคัญ: readonly ป้องกันการเปลี่ยน Reference ไม่ใช่การเปลี่ยน Object Content
public class Team {
// readonly List - Reference ไม่เปลี่ยนได้ แต่ Conent เปลี่ยนได้!
private readonly List _members = new List();
public void AddMember(string name) {
_members.Add(name); // ✅ OK - เปลี่ยน Content ของ List
}
public void ReplaceList() {
// _members = new List(); // ❌ Error - เปลี่ยน Reference
}
}
ตัวอย่างครบถ้วน
using System;
using System.Collections.Generic;
public class Employee {
// Compile-time Constant
public const string CompanyName = "TechCorp";
// Runtime Constant (readonly)
private readonly int _id;
private readonly DateTime _hireDate;
private readonly List _skills;
// Constructor - กำหนดค่า readonly ทั้งหมด
public Employee(int id, DateTime hireDate, List skills) {
_id = id;
_hireDate = hireDate;
_skills = skills ?? new List(); // 防御性编程
}
// Method ที่พยายามเปลี่ยน readonly
public void TryChangeId(int newId) {
// _id = newId; // ❌ Compile Error
}
// Method ที่แก้ไข Content ของ readonly List
public void AddSkill(string skill) {
_skills.Add(skill); // ✅ OK
}
public void Display() {
Console.WriteLine($"ID: {_id}, Hired: {_hireDate:d}, Skills: {string.Join(", ", _skills)}");
}
}
class Program {
static void Main() {
var emp = new Employee(1001, DateTime.Now, new List { "C#", "SQL" });
emp.AddSkill("Azure"); // OK - modify content
emp.Display();
// emp._id = 999; // ❌ Compile Error - readonly
}
}
Static readonly
public class Config {
// Static readonly - ค่าเดียวกันทั้ง Application, กำหนดได้ใน Static Constructor
public static readonly string ConnectionString;
public static readonly int MaxConnections = 100; // Inline init OK
static Config() {
// Static Constructor - รันครั้งเดียวก่อนใช้งานครั้งแรก
ConnectionString = LoadFromConfigFile();
}
private static string LoadFromConfigFile() {
return "Server=localhost;Database=MyDB;";
}
}
สรุป
- C# ใช้ readonly แทน
final readonly= กำหนดค่าได้ 1 ครั้ง (ใน Constructor หรือ Inline)const= Compile-time Constant (Implicit Static)readonlyReference Type = Reference คงที่ แต่ Object Content เปลี่ยนได้- ใช้
readonlyสำหรับ Dependency Injection, Configuration, Immutable Objects