Cờ beforefieldinit làm gì?


82

Cờ beforefieldinit làm gì? Khi tôi nhìn vào IL của lớp tôi, tôi thấy lá cờ này nhưng tôi không biết lá cờ này thực sự đang làm gì?

Câu trả lời:


132

Xem bài viết của tôi về vấn đề này.

Về cơ bản, beforefieldinitcó nghĩa là "kiểu có thể được khởi tạo tại bất kỳ thời điểm nào trước khi bất kỳ trường tĩnh nào được tham chiếu." Về lý thuyết , điều đó có nghĩa là nó có thể được khởi tạo rất lười biếng - nếu bạn gọi một phương thức tĩnh không chạm vào bất kỳ trường nào, thì JIT không cần phải khởi tạo kiểu.

Trong thực tế, điều đó có nghĩa là lớp được khởi tạo sớm hơn so với cách khác - nó được khởi tạo ở đầu phương thức đầu tiên có thể sử dụng nó. Hãy so sánh điều này với các loại mà khôngbeforefieldinitáp dụng đối với họ, nơi mà các loại khởi tạo có thể xảy ra ngay trước khi là người đầu tiên thực tế sử dụng.

Vì vậy, giả sử chúng ta có:

public static void DoSomething(bool which)
{
    if (which)
    {
        FirstType.Foo();
    }
    else
    {
        SecondType.Bar();
    }
}

Nếu cả hai kiểu đều beforefieldinitđược áp dụng cho chúng (trong C # chúng làm theo mặc định trừ khi kiểu có hàm tạo tĩnh) thì cả hai đều sẽ được khởi tạo ở đầu DoSomethingphương thức (thường là - nó không được đảm bảo). Nếu chúng không có beforefieldinitthì chỉ một trong số chúng sẽ được khởi tạo, dựa trên cờ.

Đây là lý do tại sao chúng ta thường sử dụng một hàm tạo tĩnh (thậm chí là một hàm trống!) Khi triển khai mẫu singleton .


"kiểu có thể được khởi tạo bất kỳ lúc nào trước khi bất kỳ trường nào được tham chiếu." nó cũng đúng cho việc chạy các phương thức tĩnh?
Royi Namir

@RoyiNamir, thông số CLI nói rằng nếu BeforeFieldInit được áp dụng thì "phương thức khởi tạo của kiểu được thực thi tại hoặc một lúc nào đó trước đó, lần đầu tiên truy cập vào bất kỳ trường tĩnh nào được xác định cho kiểu đó". Nếu thuộc tính đó bị thiếu (static .ctor) thì "lần đầu tiên truy cập vào bất kỳ trường tĩnh hoặc trường thể hiện nào của loại đó, hoặc lệnh gọi đầu tiên của bất kỳ phương thức tĩnh, trường hợp hoặc phương thức ảo nào thuộc loại đó". Vì vậy, nó không đúng với BeforeFieldInit được áp dụng trừ khi phương thức tĩnh tham chiếu đến một trường tĩnh khác.
Arman McHitarian

3
Tôi phát hiện ra rằng có một hình phạt hiệu suất cho việc sử dụng các hàm tạo tĩnh (tức là các lớp không có cờ beforefieldinit). Nếu bạn gọi các thành viên tĩnh của một lớp nhất định thường xuyên, có vẻ như thời gian chạy phải kiểm tra thêm trước mỗi lần gọi, để kiểm tra xem kiểu đã được khởi tạo chưa; beforefieldinit tránh những kiểm tra này. Một vài tiêu chuẩn là khoảng 50% nhanh hơn với beforefieldinit: codeproject.com/Articles/87991/...
Qwertie

6

Có vẻ như nó sẽ thay đổi trong 4.6

https://github.com/dotnet/coreclr/issues/1193


Thật tuyệt, điều này có nghĩa là nó sẽ đợi cho đến giây phút cuối cùng để khởi tạo trường (bất kể nó có beforefieldinithay không)?
James Ko

1
Trước lần sử dụng đầu tiên, tất cả các quyền truy cập sẽ được kiểm tra khởi tạo trước. Sau đó, khi các phương thức khác được ghép nối, mã được tạo sẽ truy cập trực tiếp vào trường. Nếu nó thuộc loại nguyên thủy thì nó thậm chí có thể được sử dụng như một hằng số thời gian JIT.
OmariO

2
Phân tích chi tiết của Jon về các thay đổi đối với kiểu khởi tạo bắt đầu từ .Net 4.0 tại đây .
RBT
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.