Static Constructor คืออะไร?
Constructor מיוחדสำหรับ Initialize Static Members หรือ ทำ Action ที่ต้องทำครั้งเดียว
เมื่อไหร่ถูกเรียก?
- ก่อนสร้าง Instance แรก ของ Class
- ก่อนเข้าถึง Static Member แรก (Field, Property, Method)
- รับประกัน: รันครั้งเดียวต่อ AppDomain, Thread-Safe
- ไม่สามารถคาดเดา/ควบคุม Timing ได้แม่นยำ
คุณสมบัติ
- ไม่มี Access Modifier (
public,privateห้ามใช้) - ไม่มี Parameter
- Class/Struct มีได้สูงสุด 1 ตัว
- ไม่สืบทอด (Inherit) ไม่ได้, Overload ไม่ได้
- ไม่สามารถเรียกโดยตรงได้ (CLR เรียกให้อัตโนมัติ)
Syntax
class MyClass
{
static MyClass()
{
// Initialization Code
Console.WriteLine("Static Constructor Executed");
}
public static int StaticField = 10;
public MyClass() // Instance Constructor
{
Console.WriteLine("Instance Constructor");
}
}
ตัวอย่างการทำงาน
using System;
class Demo
{
static Demo()
{
Console.WriteLine("Static Constructor Called");
InitializeStaticData();
}
static void InitializeStaticData()
{
Console.WriteLine("Initializing static data...");
}
public Demo()
{
Console.WriteLine("Instance Constructor Called");
}
public static void StaticMethod()
{
Console.WriteLine("Static Method Called");
}
}
class Program
{
static void Main()
{
Console.WriteLine("--- Before any access ---");
// Static Constructor ยังไม่รัน
Console.WriteLine("--- Access Static Field ---");
Console.WriteLine(Demo.StaticField); // Static Constructor รันที่นี่
Console.WriteLine("--- Create Instance 1 ---");
new Demo(); // Static Constructor ไม่รันซ้ำ
Console.WriteLine("--- Call Static Method ---");
Demo.StaticMethod(); // Static Constructor ไม่รันซ้ำ
Console.WriteLine("--- Create Instance 2 ---");
new Demo();
Console.ReadLine();
}
}
Output
--- Before any access --- --- Access Static Field --- Static Constructor Called Initializing static data... 10 --- Create Instance 1 --- Instance Constructor Called --- Call Static Method --- Static Method Called --- Create Instance 2 --- Instance Constructor Called
Use Cases (กรณีใช้งาน)
- Initialize Static Collections: Cache, Lookup Tables
- Load Configuration: อ่าน Config File ครั้งเดียว
- Native Library Init: P/Invoke Setup
- Singleton Pattern (Legacy): Thread-Safe Initialization
class Config
{
public static string ConnectionString { get; private set; }
public static int MaxRetry { get; private set; }
static Config()
{
// Load from appsettings.json / Environment Variables
ConnectionString = File.ReadAllText("conn.txt");
MaxRetry = int.Parse(Environment.GetEnvironmentVariable("MAX_RETRY") ?? "3");
}
}
Exception Handling
⚠️ Exception ใน Static Constructor = TypeInitializationException
- Type จะ Unusable ตลอด Age ของ AppDomain
- Retry ไม่ได้ ต้อง Restart Process
- ต้อง Try/Catch ภายใน Static Constructor เอง
- Type จะ Unusable ตลอด Age ของ AppDomain
- Retry ไม่ได้ ต้อง Restart Process
- ต้อง Try/Catch ภายใน Static Constructor เอง
static MyClass()
{
try
{
RiskyInitialization();
}
catch (Exception ex)
{
// Log, Set Fallback Values
_fallback = true;
// ไม่ Re-throw ไม่งั้น Type จะตาย
}
}
Static Constructor vs Static Field Initializer
| Static Field Initializer | Static Constructor |
|---|---|
static int X = Compute(); | static MyClass() { X = Compute(); } |
| Simple, Inline | Complex Logic, Multiple Statements |
| Exception → TypeInitializationException | Exception → TypeInitializationException |
| Order: ตามลำดับ Declaration | Order: ก่อน First Access |
ทั้งคู่รันก่อน First Access แต่ Static Constructor ให้ Control มากกว่า