tags:

views:

94

answers:

3

I get the error :

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

static void Main(string[] args)
{
    string s = "hello"; // Line 1
    var test = new[] { "abd", "def" }.Select(s => s.StartsWith("a")); // Line 2
}

Why?

I would have guessed that the 's' from line 1 would be shaded by the '.Select(s =>..' decleration in line 2 but - as far as I can tell - this is not the case..

PS I'm not sure that shaded it the proper term - please correct me if a better word/phrase exsists.

+3  A: 

The point is that you can already refer to the local variable s within the lambda expression - so introducing another variable called s would be pretty confusing. The C# compiler is helping you to avoid writing unreadable code.

The specification could have allowed the "extra-local" variable to just hide the local variable, certainly - but I don't think that would have been a good idea.

Jon Skeet
Why would that not be a good idea (hiding the local)? Would that not be the "normal" way?[edit: Woops. Apparently I did't know scoping very well. Now, I understand. Nevermind :)
Moberg
To avoid confusion if you really meant to reference that string, e.g. Obalix's example or something like `.Select(x => x.StartsWith(s))`
Rup
+5  A: 

You get an error for the same reason that in a normal code block (like an if statement or loop), you cannot declare variables with the same name as outside the code block.

This is different than for class variables and method variables, where you can explicitly reference class variables with the this keyword.

I think that the this keyword is the key, as there isn't any way of explicitly referencing variables that are in the same method but in different code blocks.

Dave Arkell
Spot on. It was the this.xxx hiding that lead to misunderstanding of hiding variables in scopes. Thanks :)
Moberg
+1  A: 

The declaration string s = "hello"; is declared outside the lambda expression and, therefore, accessible from within it. As a result the declaration of s => s.StartsWith("a") conflicts with the declaration of s outside the lambda expression, i.e. the compiler cannot figure out to which s you are referring in the statement s.StartsWith("a").

To show the problem consider the following code:

static void Main(string[] args)
{
    string s = "hello"; // Line 1
    var test = new[] { "abd", "def" }.Select(x => x.StartsWith("a") && s.StartsWith("h")); // Line 2
}

This will only return true in the selection if ths string in the array (represented by x within the lambda) starts with "a" and the string s starts with an "h".

BTW, your statement will only return a ICollection<bool> and not ICollection<string> as you might expect ... to return the strings starting with "a" use:

new[] { "abd", "def" }.Where(x => x.StartsWith("a"));
Obalix