Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Lấy tham chiếu nội bộ (Intern) của String trong C#

Khái niệm: String Interning

.NET duy trì một **bảng intern pool** (bảng chứa chuỗi duy nhất) cho mỗi assembly/app domain. Các chuỗi literal (hard-coded trong code) tự động được intern. Phương thức string.Intern(string str) lấy tham chiếu đến chuỗi trong pool: nếu chuỗi đã có -> trả về tham chiếu đó; nếu chưa -> thêm vào pool và trả về tham chiếu mới.

Ví dụ 1: Intern chuỗi literal

using System;

public class Demo
{
    public static void Main(string[] args)
    {
        string str1 = "David";
        string str2 = string.Intern(str1);

        Console.WriteLine($"String1: {str1}");
        Console.WriteLine($"Interned reference: {str2}");
        Console.WriteLine($"Same reference? {object.ReferenceEquals(str1, str2)}"); // True (literal đã intern)
    }
}

Kết quả

String1: David
Interned reference: David
Same reference? True

Ví dụ 2: Intern chuỗi tạo tại runtime

using System;

public class Demo
{
    public static void Main(string[] args)
    {
        string str1 = "50";
        string str2 = "100";

        Console.WriteLine($"String1: {str1}");
        Console.WriteLine($"String2: {str2}");

        // Intern str1 -> thêm vào pool nếu chưa có
        string interned = string.Intern(str1);
        Console.WriteLine($"Interned reference of str1: {interned}");
        Console.WriteLine($"Same as str1? {object.ReferenceEquals(str1, interned)}"); // True

        // Tạo chuỗi mới tại runtime (không phải literal)
        string runtimeStr = new string(new char[] { '5', '0' });
        Console.WriteLine($"\nRuntime string: {runtimeStr}");
        Console.WriteLine($"Same reference as str1? {object.ReferenceEquals(str1, runtimeStr)}"); // False

        // Intern runtime string
        string internedRuntime = string.Intern(runtimeStr);
        Console.WriteLine($"Interned runtime: {internedRuntime}");
        Console.WriteLine($"Same as str1 (literal)? {object.ReferenceEquals(str1, internedRuntime)}"); // True!
    }
}

Kết quả

String1: 50
String2: 100
Interned reference of str1: 50
Same as str1? True

Runtime string: 50
Same reference as str1? False
Interned runtime: 50
Same as str1 (literal)? True

Phương thức liên quan: string.IsInterned(string)

Kiểm tra chuỗi có trong pool **không thêm mới**. Trả về tham chiếu nếu có, null nếu không.

string s = "hello";
string interned = string.IsInterned(s); // "hello" (literal đã intern)

string runtime = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
string notInterned = string.IsInterned(runtime); // null (chưa intern)

string.Intern(runtime); // Thêm vào pool
string nowInterned = string.IsInterned(runtime); // "hello"

Khi nào dùng Intern?

  • Tiết kiệm bộ nhớ khi có **nhiều chuỗi trùng lặp** sống lâu (ví dụ: config keys, enum names, log categories).
  • So sánh tham chiếu (ReferenceEquals) nhanh hơn so sánh giá trị (Equals) -> dùng cho lookup cực nhanh.
  • Deserialization lớn: intern các chuỗi lặp lại.

Cảnh báo

  • Intern pool **không bị GC** cho đến khi AppDomain unload (hoặc process exit). Lạm dụng -> memory leak.
  • Chỉ intern chuỗi **bất biến**, sống lâu, trùng lặp nhiều.
  • Không intern input người dùng, dữ liệu ngẫu nhiên, chuỗi lớn.

So sánh hiệu năng


// So sánh 1 triệu lần
string a = "key"; string b = "key";
// Equals: ~50ms
// ReferenceEquals (sau Intern): ~5ms