2012-05-14 30 views
18

爲什麼我的參數x表現得如此不正常?Lambda Scope Clarification

  1. 示例1 - 在當前上下文中不存在。
  2. 示例2 - 無法重複使用x,因爲它在「子」範圍內定義。
  3. 示例3 - 很好。這是我困惑的部分。也許是一個不同的「孩子」範圍?

實施例1

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

創建該編譯時間錯誤:

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

我期望。

實施例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)); 

產生這個編譯時間錯誤:

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

我理解的範圍界定在這個問題,Is there a reason for C#'s reuse of the variable in a foreach?回答。不過,這是我以前從未見過的。另外,它使這個問題的答案,What is the scope of a lambda variable in C#?,不完整或錯誤。

實施例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); 

產生任何錯誤。


有了接受的答案,Eric Lippert的這些博客文章幫助我包圍了發生的事情。如果有人仍然困惑:

declaration space

simple names

+1

[這裏](http://blogs.msdn.com/b/ericlippert/archive/2009/11/02 /simple-names-are-not-so-simple.aspx)是兩個相關的[鏈接](http://blogs.msdn.com/b/ericlippert/archive/2009/11/05/simple-names-are-不太簡單 - 部分two.aspx)的主題。 – Servy

+0

[linq匿名方法(閉包)中的局部變量作用域可能的重複](http://stackoverflow.com/questions/10517964/local-variable-scope-in​​-linq-anonymous-method-closure) – Magnus

+0

可能重複的[什麼是在C#lambda變量的範圍?](http://stackoverflow.com/questions/10494074/what-is-the-scope-of-a-lambda-variable-in-c) – nawfal

回答

16

Example 1中,x在lamdba表達的局部範圍定義,並且是不可見的,以所述第三線

Example 2,現在你已經在同一個聲明範圍聲明瞭兩個名爲「x」的變量(可見性不同)

使用lambda或匿名方法,它「捕獲」它正在運行的範圍。如果你有一個與lambda定義相同範圍的本地x,那麼它會「捕獲」x來拉入lambda可以訪問的內容 - 從而產生兩個「x」的定義。你在lambda中聲明的內容不會在另一個方向上被捕獲,所以它在lambda之外是不可見的。

Example 3,現在你沒有使用僅局部於lambda之外的lambda的變量,也沒有在相同的聲明範圍內命名相同的變量。

+0

我還是不'噸得到,如何/爲什麼示例2不編譯。如果前2不會,那麼即使是前3也不會編譯。按照我的邏輯,x「int x」的第二個聲明不應該對第一個聲明有任何顧慮,因爲它是明確定義的,並且只能用於該行上定義的lambda表達式。這對我來說太過新奇了。 – MrClan

+1

@MrClan查看[此代碼](http://pastebin.com/DvDnNaPz)它與範圍界定問題類似,它可能會幫助您理解。 –

+2

@MrClan它不編譯,因爲「x => ...」聲明瞭一個x變量,而「int x = 1;」另外聲明。 lambda是一個閉包,可以引入在執行lambda時捕獲的「外部變量」。爲了捕獲這些變量,它們需要是唯一的。 「x」可能意味着在lambda中定義的x,或者在外部範圍中定義的x - 因此,編譯器不知道在「x <3」代碼中使用哪一個... –

4

子作用域(示例3)可以使用相同的變量,但父子不能重新聲明變量。

你可以得到相同的與:

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

這會失敗:

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

也不是那麼複雜,因爲它似乎是。

如果定義爲的λ表達式的參數,所述參數是唯一的LAMDA表達式的範圍內有效

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

如果你有在同一範圍爲的λ表達式所定義的第二可變,你會得到一個錯誤,因爲這個第二個變量在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 
} 
} 

在第三示例中你有2個不同的λ表達式,因此兩個不同的作用域