2012-05-14 26 views
18

Tại sao thông số của tôi x hoạt động quá thất thường?Phạm vi Lambda Làm rõ

  1. Ví dụ 1 - Không tồn tại trong ngữ cảnh hiện tại.
  2. Ví dụ 2 - Không thể sử dụng lại x vì được xác định trong phạm vi 'trẻ em'.
  3. Ví dụ 3 - Tốt. Đây là phần tôi bối rối. Có lẽ một phạm vi 'trẻ em' khác nhau?

Ví dụ 1:

List<int> list = new List<int> { 1, 2, 3, 4, 5 }; 
var result = list.Where(x => x < 3); 
Console.Write(result.ElementAt(x)); 

tạo biên dịch này thời gian lỗi:

The name 'x' does not exist in the current context

mà tôi mong đợi.

Ví dụ 2:

List<int> list = new List<int> { 1, 2, 3, 4, 5 }; 
var result = list.Where(x => x < 3); 
int x = 1; 
Console.Write(result.ElementAt(x)); 

sản xuất lỗi thời gian biên dịch này:

A local variable named 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'child' scope to denote something else

tôi hiểu Phạm vi như đã trả lời trong câu hỏi này, Is there a reason for C#'s reuse of the variable in a foreach?. Tuy nhiên, đây là điều tôi chưa bao giờ thấy trước đây. Ngoài ra, nó làm cho câu trả lời cho câu hỏi này, What is the scope of a lambda variable in C#?, không đầy đủ hoặc sai.

Ví dụ 3:

List<int> list = new List<int> { 1, 2, 3, 4, 5 }; 
List<string> stringList = new List<string> { "A", "B" }; 
var result = list.Where(x => x < 3); 
var result2 = stringList.Where(x => x != "A"); 

Console.Write(result2); 

Không có lỗi sản xuất.


Với câu trả lời được chấp nhận, những bài đăng trên blog này từ Eric Lippert đã giúp tôi thu hút sự chú ý của mình về những gì đang diễn ra. Nếu ai vẫn còn bối rối:

declaration space

simple names

+1

[Đây] (http://blogs.msdn.com/b/ericlippert/archive/2009/11/02 /simple-names-are-not-so-simple.aspx) là hai [liên kết] có liên quan (http://blogs.msdn.com/b/ericlippert/archive/2009/11/05/simple-names-are- không-so-đơn giản-part-two.aspx) về chủ đề này. – Servy

+0

có thể trùng lặp của [phạm vi biến cục bộ trong phương thức ẩn danh linq (đóng)] (http://stackoverflow.com/questions/10517964/local-variable-scope-in-linq-anonymous-method-closure) – Magnus

+0

bản sao có thể có của [ Phạm vi của biến lambda trong C# là gì? (Http://stackoverflow.com/questions/10494074/what-is-the-scope-of-a-lambda-variable-in-c) – nawfal

Trả lời

16

Trong Example 1, x được xác định trong phạm vi địa phương của biểu thức lamdba và không nhìn thấy được vào dòng thứ ba

Trong Example 2, bây giờ bạn đã khai báo hai biến có tên "x" ở cùng một phạm vi khai báo (mức hiển thị khác nhau)

Với một lambda hoặc phương thức ẩn danh, nó "bắt" phạm vi mà nó đang chạy. Nếu bạn có một x địa phương trong cùng phạm vi với định nghĩa lambda, thì nó "bắt" rằng x để kéo vào những gì lambda có thể truy cập - do đó dẫn đến hai định nghĩa "x". Những gì bạn khai báo trong lambda không bị bắt theo hướng khác để nó không thể nhìn thấy bên ngoài lambda.

Trong Example 3, Bây giờ bạn không sử dụng biến chỉ cục bộ lambda bên ngoài lambda và không đặt tên cho một cái gì đó giống nhau ở cùng phạm vi khai báo.

+0

Tôi vẫn không ' t nhận được, làm thế nào/tại sao ví dụ 2 không biên dịch. Nếu ví dụ ex-2 thì không phải ex-3 cũng không được biên dịch. Theo logic của tôi, khai báo thứ 2 của x "int x" không nên có bất kỳ mối quan tâm nào với cái thứ nhất, vì nó được xác định rõ ràng và chỉ có sẵn cho biểu thức lambda được định nghĩa trên dòng đó. Điều này thật là mới mẻ và kỳ lạ đối với tôi. – MrClan

+1

@MrClan xem [mã này] (http://pastebin.com/DvDnNaPz) nó tương tự như vấn đề phạm vi và nó có thể giúp bạn hiểu. –

+2

@MrClan nó không biên dịch vì "x => ..." khai báo một biến x, và "int x = 1;" tuyên bố khác. Các lambda là một đóng cửa có thể mang lại "biến bên ngoài" được bắt giữ khi lambda được thực hiện. Để các biến đó được bắt, chúng cần phải là duy nhất. "x" có thể có nghĩa là x được định nghĩa trong lambda, hoặc x được định nghĩa trong phạm vi bên ngoài - do đó, trình biên dịch không biết cái nào để sử dụng trong mã "x <3" ... –

4

Phạm vi con (ví dụ 3) có thể sử dụng cùng một biến, nhưng cha mẹ và con không thể khai báo lại biến.

Bạn có thể nhận được cùng với cho:

// Child scopes 
for (int i = 1; i < 10; i++){ /* do something */ } 
for (int i = 1; i < 10; i++){ /* do something else */ } 

này sẽ thất bại:

// Child and parent 
for (int i = 1; i < 10; i++){ /* do something */ } 
int i = 33; 
2

Nó không phải là quá phức tạp như nó có vẻ là.

Nếu bạn định nghĩa một tham số cho một biểu thức lamda, tham số chỉ có giá trị trong phạm vi của biểu thức lamda

(int x) => 
{ 
    //x is only valid inside this scope 
} 

Nếu bạn có một biến thứ hai với quy định trong phạm vi tương tự như khái niệm lamda , bạn sẽ gặp lỗi, vì biến thứ hai này cũng hợp lệ trong phạm vi biểu thức lamda.

void Foo() 
{ 

int y; 

//y is valis in the scope of foo 

(int x) => 
{ 
    //x is only valid inside this scope 
    //y is valid in the scope of foo and the lamda expression 
} 
} 

Trong ví dụ thứ ba bạn có 2 biểu thức lamda khác nhau và do đó hai lĩnh vực khác nhau

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