2009-04-15 36 views

Trả lời

14

Các trường được tự động khởi tạo về số không logic cho loại; điều này là ngầm định. Các biến phải tuân theo "phân bổ xác định", do đó, phải được gán trước khi có thể đọc được.

ECMA 334v4

§17.4.4 Dòng khởi

Giá trị ban đầu của một trường, cho dù đó là một lĩnh vực tĩnh hoặc một instance field , là giá trị mặc định (§12.2) của loại của trường. Không thể để quan sát giá trị của trường trước khởi tạo mặc định này đã xảy ra và do đó, trường không bao giờ là "chưa được khởi tạo".

§12. Các biến số

... Một biến chắc chắn sẽ được gán (§12.3) trước khi giá trị của nó có thể đạt được. ...

+0

Đó chỉ là lặp lại câu hỏi. Nhưng tại sao? –

+0

@YairHalberstadt tùy thuộc vào việc "tại sao?" có nghĩa là quy tắc hoặc lý do đằng sau quy tắc. Tôi trả lời câu hỏi đầu tiên, câu trả lời cho câu hỏi; cho lần thứ hai: bởi vì vào thời điểm bạn đã xem xét việc tạo chuỗi, các phương thức ảo được gọi trong quá trình xây dựng và thực tế là các nhà xây dựng cơ sở ở cấp độ IL có thể được gọi bất kỳ lúc nào trong chuỗi cuộc gọi - hầu như không thể nói bất cứ điều gì hợp lý về khởi tạo trường; bằng nhau, các trường có thể bị chồng chéo làm cho không gian trống quan trọng hơn, do đó không yêu cầu kỹ thuật init - tương phản ... –

+0

@YairHalberstadt biến cục bộ, có kiểm tra chuyển nhượng rất dễ dàng, nơi uninitialized thường có nghĩa là lỗi và có thể bỏ qua zeroing (mặc dù thời gian chạy hiện tại không bao giờ thực hiện, IIRC). –

4

Nó thực sự không nên. Lỗi của bạn phải nằm trên dòng thứ hai, không phải là lỗi đầu tiên và phải là vì bạn đã SỬ DỤNG CNTT trước khi bạn khởi tạo nó.

Trình biên dịch đang trợ giúp bạn tại đây.

Vì vậy, đừng khởi tạo chúng như một thói quen, thay vào đó hãy để trình biên dịch giúp bạn!

Điều tuyệt vời về việc này là nó sẽ kiểm tra đường dẫn cho bạn. Nếu bạn có một tuyên bố chuyển đổi với 3 trường hợp mà mỗi bộ giá trị nhưng bạn quên đặt nó trong "mặc định" của bạn nhưng sử dụng nó sau đó nó sẽ cảnh báo bạn rằng bạn đã bỏ lỡ một con đường.

Nếu bạn khởi tạo biến thành = 0, bạn lấy lợi ích đó đi.

+0

Tôi cũng sử dụng test1 trước khi tôi khởi tạo nó, nhưng đó là ok –

+0

Có, kiểm tra tương tự không hữu ích với biến lớp - không có cách nào để theo dõi đường dẫn trừ khi bạn đặt chúng cuối cùng, sau đó phải đảm bảo rằng chúng điền vào trong các nhà xây dựng (một ý tưởng tốt khi có thể) –

+0

Mặc dù kiểm tra đường dẫn của nó không phải là quá ưa thích. Ví dụ: giả sử u có một cái gì đó như thế: 'bool a, b = true; if (b) a = true; bool c = a; '. Câu lệnh thứ ba ** sẽ ** tạo ra lỗi, mặc dù chúng ta, con người, rõ ràng thấy rằng 'a' ** ** sẽ được khởi tạo sau đó. Trình biên dịch không nhìn vào các điều kiện bên trong - ngay cả khi chúng đơn giản và luôn đúng. (Và vì vậy nó cũng áp dụng cho các trường hợp phức tạp hơn). – Sushi271

2

Như Marc cho biết, đó là những gì đặc điểm kỹ thuật nói. Lý do này là một điều tốt là có một số lý do hợp lệ để rời khỏi một thành viên uninitialized chứ không phải là một biến địa phương, có đời là bị ràng buộc bởi phương pháp nó được in. Chủ yếu là bạn chỉ muốn điều này vì lý do hiệu suất, nếu biến là tốn kém để khởi tạo, và chỉ nên được khởi tạo trong các tình huống sử dụng cụ thể. Về phần tôi, tôi muốn tránh những thành viên chưa được khởi tạo cho đến khi lưng tôi thực sự chống lại bức tường! Đối với các biến cục bộ, nó cũng dễ dàng hơn để phát hiện xem tất cả các đường dẫn mã có khả năng dẫn đến khởi tạo, trong khi không có chẩn đoán tốt để xác định xem tất cả các đường dẫn mã trên toàn bộ chương trình có đảm bảo khởi tạo trước khi sử dụng hay không. Một câu trả lời hoàn toàn chính xác là impossible in both cases, như tất cả các sinh viên CS nên biết.

12

Mở rộng câu trả lời của Mark, khởi tạo biến cục bộ cũng liên quan đến quy trình xác minh .CLI yêu cầu rằng trong bất kỳ mã xác minh nào (có nghĩa là, các mô-đun không yêu cầu bỏ qua quá trình xác minh bằng cách sử dụng thuộc tính SkipVerfication từ thuộc tính SecurityPermission), tất cả các biến cục bộ phải được khởi tạo trước khi chúng được sử dụng. Nếu không làm như vậy sẽ dẫn đến việc bị ném VerficationException.

Thú vị hơn, là trình biên dịch tự động thêm cờ .locals init vào mọi phương pháp sử dụng biến cục bộ. Cờ này làm cho trình biên dịch JIT tạo mã để khởi tạo tất cả các biến cục bộ thành các giá trị mặc định của chúng. Có nghĩa là, mặc dù bạn đã khởi tạo chúng trong mã của riêng bạn, JIT sẽ tuân thủ cờ .locals init và tạo mã khởi tạo thích hợp. Điều này "khởi tạo trùng lặp" không ảnh hưởng đến hiệu suất vì trong các cấu hình cho phép tối ưu hóa, trình biên dịch JIT sẽ phát hiện sự trùng lặp và xử lý nó một cách hiệu quả là "mã chết" (thường trình khởi tạo tự động sẽ không xuất hiện trong các hướng dẫn lắp ráp được tạo).

Theo Microsoft (cũng được sao lưu bởi Eric Lippert để trả lời câu hỏi trên blog của mình), trong hầu hết các trường hợp, khi người lập trình không khởi tạo biến cục bộ của họ, họ không làm như vậy vì họ chuyển tiếp môi trường cơ bản để khởi tạo biến của chúng là giá trị mặc định, nhưng chỉ vì chúng "quên", do đó, gây ra các lỗi logic đôi khi ảo ảnh.
Vì vậy, để giảm xác suất cho các lỗi của bản chất này xuất hiện trong mã C#, trình biên dịch vẫn khẳng định bạn sẽ khởi tạo các biến cục bộ của bạn. Mặc dù nó sẽ thêm cờ .locals init vào mã IL được tạo.

Giải thích toàn diện hơn về chủ đề này có thể được tìm thấy tại đây: Behind The .locals init Flag

Các vấn đề liên quan