Tìm hiểu về thuật ngữ ‘Lazy Initialization’ trong C#

‘Lazy Initialization’ là một thuật ngữ quen thuộc nói về phương pháp trì hoãn việc khởi tạo (hoặc nạp) dữ liệu cho đến khi chúng thực sự cần đến. Việc này rất hữu ích khi dữ liệu rất lớn và bạn không muốn người dùng tốn một tách cafe, ngồi chờ đợi những thứ chưa được sử dụng nhưng lại được nạp lên một cách … ‘xa xỉ’.

Theo cách thông thường, đây là một kĩ thuật rất đơn giản và áp dụng rất thường xuyên. Ví dụ như một property như sau hẳn là rất quen thuộc với đa số lập trình viên:

class Foo
{
    private object _lazyData = null;
    public object LazyData{
        get {
            if (_lazyData == null)
                _lazyData = LoadData();
            return _lazyData;
        }
    }
}

Trong C#, bạn không cần phải xử lý thủ công như trên để đạt được mục đích, hãy dành việc này cho .NET qua các class mà tôi giới thiệu qua hai ví dụ sau:
System.Lazy

Việc khởi tạo một đối tượng cần truyền vào một delegate Func để trả về dữ liệu (thay vì là dữ liệu trực tiếp). Khi đó dữ liệu vẫn chưa được nạp cho đến khi bạn lấy dữ liệu thông qua property lazyObj.Value.

static void Main(string[] args)
{
    var lazyObj = new Lazy<object>(() => { return LoadData(); });

    Console.WriteLine(lazyObj);         // (1)
    Console.WriteLine(lazyObj.Value);   // (2) (3)

    Console.ReadLine();
}

static string LoadData(){
    System.Console.WriteLine("Start loading data.");
    return "This is a 'HUGE data'.";
}
// Output:
// Value is not created. 	(1)
// Start loading data.		(2)
// This is the 'data'.		(3)

System.Threading.LazyInitializer

Nếu bạn không thích dữ liệu được wrap vào lớp Lazy, bạn có thể sử dụng một phương pháp trực tiếp hơn thông qua phương thức tĩnh EnsureInitialized() của lớp LazyInitializer. Phương thức này sẽ kiểm tra và nạp dữ liệu nếu biến (lazyObj) chưa có giá trị.

static void Main(string[] args)
{
    object lazyObj = null;
    Console.WriteLine("Data has not been loaded.");

    LazyInitializer.EnsureInitialized(ref lazyObj, () => { return LoadData(); });
    Console.WriteLine(lazyObj);

    Console.ReadLine();
}

static string LoadData(){
    System.Console.WriteLine("Start loading data.");
    return "This is a 'HUGE data'.";
}

// OUTPUT:
// Data has not been loaded yet.
// Start loading data.
// This is a 'HUGE data'.

Bạn cũng có thể sử dụng một cờ kiểu boolean để xác định việc dữ liệu đã được nạp hay chưa bằng cách dùng overload sau của EnsureInitialized():

object lazyObj = 1;
bool loaded = false;
object datalock = new object();

LazyInitializer.EnsureInitialized(ref lazyObj, ref loaded, ref datalock, () => { return LoadData(); });

YinYangIt’s Blog