2010-03-25 60 views
16

Tôi có đoạn mã sau:Non khởi tạo biến trong C#

class Foo 
{ 

    public Foo() 
    { 
     Bar bar; 
     if (null == bar) 
     { 

     } 
    } 
} 

class Bar { } 

guru Mã sẽ đã thấy rằng điều này mang lại một lỗi. Bar có thể không được khởi tạo trước câu lệnh if.

Vì vậy, bây giờ tôi tự hỏi: những gì là vlaue của quán bar, nó không nên là null? Chúng không được đặt thành null? (nullpointer?)

+0

Tại thời điểm đó, Bar trỏ đến một vị trí trong ngăn xếp chứ không phải đống. Đó là lý do nó cần một giá trị –

+0

Và các lớp học được khởi tạo trên heap phải không? Và cấu trúc không. Chính xác? – Snake

+0

Nhưng mã được thực thi trong ngữ cảnh của Constructor –

Trả lời

32

Không, biến cục bộ không có giá trị mặc định . Họ phải được chắc chắn được gán trước khi bạn đọc chúng. Điều này làm giảm cơ hội bạn sử dụng biến số nghĩ rằng bạn đã đưa ra một giá trị hợp lý, khi thực sự nó có một số giá trị mặc định. Điều này không thể được thực hiện ví dụ hoặc biến tĩnh bởi vì bạn không biết trong những phương pháp thứ tự sẽ được gọi.

Xem phần 5.3 của thông số C# 3.0 để biết thêm chi tiết về phân bổ xác định.

Lưu ý rằng điều này không liên quan gì đến việc này là biến loại tham chiếu. Điều này sẽ không biên dịch trong cùng một cách:

int i; 
if (i == 0) // Nope, i isn't definitely assigned 
{ 
} 

Theo như ngôn ngữ là có liên quan, dù sao ... rõ vị trí lưu trữ trong bộ nhớ có một cái gì đó trong nó, nhưng nó không liên quan và thực hiện cụ thể. Có một cách bạn có thể tìm ra giá trị đó là gì, bằng cách tạo phương thức có thông số out nhưng sau đó sử dụng IL để xem giá trị của tham số đó trong phương thức mà không phải đặt giá trị khác. CLR không bận tâm gì cả. Sau đó, bạn có thể gọi gọi phương thức đó chuyển qua biến không được gán chắc chắn và bạn có thể phát hiện giá trị - có khả năng là giá trị "tất cả số 0" về cơ bản.

Tôi nghi ngờ rằng đặc điểm kỹ thuật CLI thực hiện thực thi các biến cục bộ có giá trị mặc định - nhưng tôi phải kiểm tra. Trừ khi bạn đang làm những điều xấu xa như trên, nó không quan trọng với bạn trong C#.

+6

Nó được kiểm soát bởi cờ * localsinit * trên siêu dữ liệu của phương thức. Xem phần Phân vùng III 3.47 "localloc" để biết chi tiết. Tôi dường như nhớ lại rằng CLR luôn luôn khởi tạo bộ nhớ ngăn xếp bằng không bất kể. Hoặc có lẽ nó luôn luôn như vậy khi một trình gỡ rối được đính kèm? Tôi không chắc. Trong mọi trường hợp, người dân địa phương quan sát thấy trong trạng thái uninitialized của họ thông qua các phương tiện lén lút khá nhiều luôn luôn dường như có giá trị mặc định của họ. –

2

Biến cục bộ không được chỉ định giá trị mặc định. Bạn phải khởi tạo chúng trước khi sử dụng chúng. Bạn explicityly có thể khởi tạo để null mặc dù:

public Foo() 
{ 
    Bar bar = null; 
    if (null == bar) 
    { 

    } 
} 
7

Fields (biến trên lớp/struct) được khởi tạo null/zero/etc. Các biến cục bộ ... tốt - kể từ (bằng cách "phân định rõ ràng") bạn không thể truy cập chúng mà không gán, không có cách trả lời hợp lý; đơn giản, nó không được định nghĩa vì nó là không thể. Tôi tin rằng chúng xảy ranull/zero/etc (có thể kích hoạt bằng cách hack một số mã out thông qua tạo IL động), nhưng đó là chi tiết triển khai.


Đối với thông tin, đây là một số mã crafy đó cho thấy giá trị của một biến chính thức uninitialised:

using System; 
using System.Reflection.Emit; 
static class Program 
{ 
    delegate void Evil<T>(out T value); 
    static void Main() 
    { 
     MakeTheStackFilthy(); 
     Test(); 
    } 
    static void Test() 
    { 
     int i; 
     DynamicMethod mthd = new DynamicMethod("Evil", null, new Type[] { typeof(int).MakeByRefType()}); 
     mthd.GetILGenerator().Emit(OpCodes.Ret); // just return; no assignments 
     Evil<int> evil = (Evil<int>)mthd.CreateDelegate(typeof(Evil<int>)); 
     evil(out i); 
     Console.WriteLine(i); 
    } 
    static void MakeTheStackFilthy() 
    { 
     DateTime foo = new DateTime(); 
     Bar(ref foo); 
     Console.WriteLine(foo); 
    } 
    static void Bar(ref DateTime foo) 
    { 
     foo = foo.AddDays(1); 
    } 
} 

Các IL chỉ hiện một "ret" - nó không bao giờ gán bất cứ điều gì.

+0

Tôi đã không phát hiện ra rằng bạn đã tìm cách xác định giá trị bằng cách sử dụng tham số ngoài - tôi chỉ cần thêm vào câu trả lời của tôi. Ác, đồ vật khó chịu. –

+0

Tôi không biết đây có phải là một câu hỏi ngu ngốc hay không, nhưng tại sao hành vi lại khác với các trường so với các biến cục bộ? Có phải do phạm vi, nghĩa là biến cục bộ chỉ hợp lệ trong một hàm không? Hoặc là có một lý do khác? –

+1

@Jon - bạn thậm chí không cần điều đó; nếu bạn có một loại đại biểu là "ra giá trị MyType", chỉ cần tạo một 'DynamicMethod' với IL =" ret ", gọi' CreateDelegate' và gọi ủy nhiệm "out myVariable". Sau đó kiểm tra biến. Không cần phải làm công việc khó khăn trong phương pháp năng động. –

1

Biến cục bộ không được chỉ định giá trị mặc định, thậm chí không phải là null.

1

Không, biến cục bộ không được đặt tự động thành 0 (mặc định).

Nhưng vì bạn (luôn luôn) gặp lỗi đó, nó thực sự không quan trọng. Nếu nó có giá trị khác thì trình biên dịch sẽ không bao giờ cho phép bạn tìm ra.

Không được nhầm lẫn với biến trường (thành viên nhóm), chúng được khởi tạo thành giá trị mặc định của loại (0/null/false/...).

1

Giá trị của bar không xác định. Có không gian được phân bổ cho nó trên ngăn xếp, nhưng không gian không được khởi tạo cho bất kỳ giá trị nào để nó chứa bất kỳ thứ gì đã xảy ra ở đó trước đó.

(Biến địa phương tuy nhiên có thể được tối ưu hóa để sử dụng một thanh ghi thay vì ngăn xếp không gian, nhưng nó vẫn không xác định.)

Trình biên dịch sẽ không cho phép bạn sử dụng giá trị không xác định, nó có để có thể xác định rằng biến được khởi tạo trước khi bạn có thể sử dụng nó.

Để so sánh, VB khởi tạo biến cục bộ. Trong khi điều này đôi khi có thể thực tế, nó cũng có thể có nghĩa là bạn không sử dụng biến trước khi bạn đã cho nó một giá trị có ý nghĩa, và trình biên dịch không thể xác định nếu đó là những gì bạn có ý định làm hay không.

0

Nó không quan trọng bởi vì không có mã nào được biên dịch bởi bất kỳ trình biên dịch nào thực hiện C#.

Nếu có giá trị mặc định, thì giá trị đó sẽ được tổng hợp. Nhưng không có biến nào cho các biến cục bộ.

0

Bên cạnh "độ chính xác", khởi tạo biến cục bộ cũng liên quan đến quy trình xác minh của CLR.
Để biết thêm chi tiết, hãy xem câu trả lời của tôi cho câu hỏi tương tự này: Why must local variables have initial values

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