2009-03-04 30 views

Trả lời

108

Xem my article về vấn đề này.

Về cơ bản, beforefieldinit có nghĩa là "loại có thể được khởi tạo bất kỳ lúc nào trước khi bất kỳ trường tĩnh nào được tham chiếu". Trong lý thuyết có nghĩa là nó có thể được rất lười biếng khởi tạo - 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, JIT không cần phải khởi tạo loại.

Trong thực tế nó có nghĩa là lớp được khởi tạo trước đó hơn nó sẽ khác - đó là okay cho nó được khởi tạo vào lúc bắt đầu của phương pháp đầu tiên mà thể sử dụng nó. So sánh điều này với các loại không có áp dụng beforefieldinit cho chúng, nơi khởi tạo loại phải xảy ra ngay trước khi sử dụng thực tế đầu tiên.

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 loại có beforefieldinit áp dụng cho họ (mà trong C# họ làm theo mặc định trừ loại có một constructor tĩnh) sau đó họ sẽ cả được khởi tạo vào lúc bắt đầu của phương thức (thông thường - nó không được bảo đảm). Nếu họ không có beforefieldinit thì chỉ một trong số đó sẽ được khởi chạy, dựa trên cờ.

Đây là lý do tại sao người ta thường sử dụng một hàm tạo tĩnh (ngay cả một hàm tạo rỗng) khi implementing the singleton pattern.

+0

_ "loại có thể được khởi tạo tại bất kỳ điểm nào trước khi bất kỳ lĩnh vực được tham chiếu." _ Là nó cũng đúng cho việc chạy các phương pháp tĩnh? –

+0

@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 hiện tại, hoặc đôi khi 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 loại đó". Nếu thuộc tính đó bị bỏ qua (static .ctor) thì "truy cập đầu tiên vào bất kỳ trường tĩnh hoặc trường nào của kiểu đó, hoặc lần đầu tiên yêu cầu bất kỳ phương thức tĩnh, dụ hoặc ảo nào của kiểu đó". Vì vậy, nó không đúng đối 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. –

+2

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 thực hiện kiểm tra thêm trước mỗi cuộc gọi, để kiểm tra xem kiểu đã được khởi tạo chưa; beforefieldinit tránh các kiểm tra này. Một vài điểm chuẩn nhanh hơn khoảng 50% với beforefieldinit: http://www.codeproject.com/Articles/87991/Dynamic-interfaces-in-any-NET-language – Qwertie

4

Hình như nó sẽ thay đổi trong 4,6

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

+0

Tuyệt vời, vậy điều này có nghĩa là nó sẽ đợi cho đến khi giây phút cuối cùng để khởi tạo trường (bất kể nó có 'beforefieldinit' hay không)? –

+1

Trước khi sử dụng đầu tiên tất cả các truy cập sẽ được bắt đầu bằng kiểm tra khởi tạo. Sau đó, khi các phương thức khác được trích xuất, mã được tạo sẽ truy cập trực tiếp vào trường. Nếu nó là một kiểu 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

+0

Phân tích chi tiết của Jon về những thay đổi về khởi tạo kiểu bắt đầu .Net 4.0 [ở đây] (https: //codeblog.jonskeet.uk/2010/01/26/type-initialization-changes-in-net-4-0 /). – RBT