2010-02-23 39 views
6

Chỉ tò mò về mã bên dưới.Tạo các đối tượng trong Loop C#

for (int i=0; i<9; i++) 
{ 
    ClassA objectA = new ClassA(); 
} 

hoặc

ClassA objectA; 
for (int i=0; i<9; i++) 
{ 
    objectA = new ClassA(); 
} 

Bất cứ ý tưởng là có bất kỳ sự khác biệt cho cả mã? từ kiến ​​thức của tôi cả hai sẽ tạo ra các trường hợp khác nhau mỗi lần như vậy số lượng các trường hợp sẽ giống nhau .. Bất kỳ ý tưởng?

Trả lời

25

phạm trù sang một bên (ví dụ: cho dù biến tồn tại bên ngoài vòng lặp) có thường có sự khác biệt, kể từ biến .NET thực sự (trong IL) tất cả tại bắt đầu của phương pháp này anyway. Tuy nhiên, có một ngoại lệ: nếu bạn chụp biến (thành một phương thức ẩn danh/lambda), sau đó nó hoạt động khác nhau - chụp được xây dựng để tôn trọng khai báo C#. Vì vậy:

List<Action> actions = new List<Action>(); 
ClassA objectA; 
for (int i=0;i<9;i++) 
{ 
    objectA= new ClassA(); 
    actions.Add(delegate { Console.WriteLine(objectA.GetHashCode()); });   
} 
foreach(Action action in actions) action(); 

và:

List<Action> actions = new List<Action>(); 
for (int i=0;i<9;i++) 
{ 
    ClassA objectA= new ClassA(); 
    actions.Add(delegate { Console.WriteLine(objectA.GetHashCode()); });   
} 
foreach(Action action in actions) action(); 

sẽ làm những việc khác nhau (các bản in đầu tiên cùng địa chỉ dựa trên băm mã 9 lần; các bản in thứ hai 9 khác nhau băm địa chỉ trụ sở -codes, cho biết rằng trong vòng lặp thứ hai, chúng tôi đã ghi lại các biến số khác nhau, thay vì một biến duy nhất).

Trong cả hai trường hợp, có 9 ClassA đối tượng được tạo - đơn giản là chúng ta không thể thấy 8 trong số chúng nữa trong trường hợp đầu tiên.

+4

+1 vì điều đó thực sự thú vị. –

+1

Như thường lệ Marc, bạn cung cấp vượt quá mong đợi. Phạm vi khi làm lambda là một hạt khó khăn để crack đôi khi.Tôi chắc chắn tất cả chúng ta đã bị đốt cháy bởi vấn đề phạm vi mà bạn chỉ ra ở trên. Tôi biết tôi có. Chúc mừng! – TheSoftwareJedi

0

Sự khác biệt lớn nhất là nếu bạn tạo một đóng cửa bên trong vòng lặp bắt giữ đối tượngA và đóng cửa đó thoát khỏi vòng lặp. Nói cách khác, nếu objectA bằng cách nào đó có thể nhìn thấy bên ngoài vòng lặp, thì trường hợp đầu tiên sẽ có 9 giá trị khác nhau sau khi vòng lặp kết thúc, trong khi giá trị thứ hai sẽ chỉ có giá trị cuối cùng khi vòng lặp kết thúc.

Ví dụ,

for (int i = 0; i < 9; i++) 
{ 
    ClassA objectA = new ClassA(); 
    someFunc(() => objectA); 
} 

có thể có kết quả rõ rệt khác với

ClassA objectA; 
for (int i = 0; i < 9; i++) 
{ 
    objectA = new ClassA(); 
    someFunc(() => objectA); 
} 
+0

Tại sao bạn đặc biệt đánh dấu các đóng cửa ở đây? 'someFunc (objectA)' cũng có thể lưu một tham chiếu tới từng đối tượng, ví dụ, nếu 'someFunc' là một hàm' Add' của Bộ sưu tập. –

+0

'someFunc (objectA)' sẽ chuyển một tham chiếu đến một đối tượng khác nhau mỗi lần lặp qua vòng lặp; 'someFunc (() => objectA)' sẽ truyền tham chiếu giống nhau hoặc khác nhau tùy thuộc vào nơi 'ClassA' được khai báo. – Gabe

13

Sự khác biệt duy nhất là trong ví dụ thứ hai, ví dụ tạo ra cuối cùng sẽ vẫn có thể truy cập sau vòng lặp

0

Sự khác biệt giữa hai điều này là sau khi vòng lặp for hoàn thành, thể hiện của ClassA từ thứ hai e iteration cuối cùng (i = 8) sẽ có sẵn cho phần còn lại của hàm, trong khi trong phiên bản đầu tiên, nó sẽ không được.

0

Sự khác biệt duy nhất là đối tượngA sẽ trỏ đến ví dụ ClassA sau vòng lặp thứ hai. Trong cả hai trường hợp, 9 đối tượng sẽ được tạo ra, nhưng trong trường hợp đầu tiên tất cả chúng sẽ bị hủy và thứ hai - đối tượng cuối cùng sẽ không được.

2

Thực ra, vì bạn không bao giờ lưu tham chiếu đến đối tượng mà bạn tạo, mỗi khi bạn ghi đè đối tượngA, bạn sẽ loại bỏ ví dụ trước đó.

Tuy nhiên, trong trường hợp:

for (int i=0;i<9;i++) 
{ 
    ClassA objectA = new ClassA(); 
} 

objectA không tồn tại bên ngoài phạm vi của vòng lặp, và tất cả các đối tượng mà bạn đã tạo sẽ bị xóa bởi các bộ thu rác. Nó sẽ là một lỗi cú pháp để tham khảo objectA bên ngoài vòng lặp.

Ngược lại, trong trường hợp:

ClassA objectA; 
for (int i=0;i<9;i++) 
{ 
    objectA= new ClassA(); 
} 

objectA là một định danh hợp lệ bên ngoài vòng lặp, và các ví dụ cuối cùng của ClassA tạo ra sẽ còn lại sau khi vòng lặp kết thúc.

1

Trong đoạn đầu tiên, đối tượngA sẽ không thể truy cập được bên ngoài vòng lặp. Do đó, nếu bạn đã viết:

for (int i=0;i<9;i++) 
{ 
    ClassA objectA = new ClassA(); 
} 
// This will not compile. 
objectA.DoSomething(); 

Bạn sẽ nhận được lỗi biên dịch. Tuy nhiên, nếu bạn đã viết mã là:

ClassA objectA; 
for (int i=0;i<9;i++) 
{ 
    objectA= new ClassA(); 
} 
// This will compile. 
objectA.DoSomething(); 

Đoạn mã thứ hai sẽ biên dịch (giả sử ClassA có phương thức có tên DoSomething()).

0

prakash, chỉ vì mục đích chính xác/đầy đủ: không đúng sự thật là các biến sẽ không thể truy cập được sau khi vòng lặp kết thúc. Chúng tôi thường giả định rằng đối tượng được tạo ra rất đơn giản, trong đó có thể là không phải như vậy. Ví dụ, bạn có thể thêm đối tượng vào danh sách chung bên trong hàm tạo, vì vậy tất cả các đối tượng vẫn có thể truy cập sau khi kết thúc vòng lặp.

Sự khác biệt có liên quan là điểm được chỉ ra bởi kbrinley, vì bạn không thể sử dụng biến (tham chiếu đối tượng) nằm ngoài phạm vi (bất kể từ {đến}) trong ví dụ đầu tiên. Kể từ lần thứ hai bạn khai báo biến ngoài vòng lặp, bạn vẫn có thể sử dụng biến.

Như Marc Gravell nói, IL tạo ra là như nhau cho cả hai, vì vậy không nên có sự khác biệt về hiệu suất, bộ nhớ nghề nghiệp, vv cho vòng lặp. [1]


1: Vì trên ví dụ thứ hai chắc chắn giữ lại một tham chiếu đến biến cuối cùng, Garbage Collector sẽ không thể giải phóng không gian của nó. Vì vậy, sau khi vòng lặp kết thúc, sẽ có sự khác biệt tinh tế.

2

Số lượng cá thể không được tăng lên dựa trên các mã. Cả hai vòng lặp chỉ là khởi tạo lại cùng một biến khác biệt duy nhất là trên vòng lặp đầu tiên biến cá thể không thể truy cập khi nó kết thúc vòng lặp không giống như vòng thứ hai trong đó biến được khai báo bên ngoài vòng lặp.

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