This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Child Scope & CS0136
C# Variable Scoping
Though I have been using C# for quite some time, I have just stumbled upon this error.
If I have the following:
if(true)
{
int x = 0;
}
int x = 0;
I get an error that says: 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.
And if I do this:
if(true)
{
int x = 0;
}
x = 0;
I get an error that says: The name 'x' does not exist in the current context.
I can understand having one or the other, but why do both of these errors exist? Is there a way around the first option? I find it very annoying.
Thanks.
Both of these errors exist to stop you from making mistakes or causing your colleagues to want to kill you.
The first fails because it's confusing to have two identically named local variables both in scope at a time.
The second fails because the variable's scope is the if statement, and you're trying to access it outside that scope.
If you want a single variable which you can use both inside and outside the block, you just need to declare it before the block:
int x;
if (true)
{
x = 0;
}
x = 0;
If you actually want two separate variables to be in scope at the same time (within the block), then give them different names - thereby avoiding later confusion.
EDIT: You can declare multiple local variables with the same name in a single method, but they have to have separate scopes. For example:
public void Foo(IEnumerable<string> values)
{
double sum = 0;
foreach (string x in values)
{
int z = x.Length;
sum += z;
}
foreach (string x in values)
{
double z = double.Parse(x);
sum += z;
}
}
Personally I don't tend to use this ability very often - at least not with different types - when the variables have meaningful names and methods are short. But it's absolutely legitimate, and can certainly be useful sometimes.
In the first case, the problem is that your int x outside the { } block has a global scope that encloses the context inside { }; therefore you are re-declaring a variable with the same name.
In the second case; x does not exist as it is only defined inside { }
Related
This question already has answers here:
C# local variable scope [duplicate]
(5 answers)
Closed 2 years ago.
So I was doing a simple for loop and suddenly i got an scope error. if I change the i in int i = 100 it dissapears but I just want to understand why this happens.
The error appears int the for(int i = 0; i<10; i++)
A local parameter called 'i' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
class Class1
{
static void Hi()
{
for(int i = 0; i<10; i++)
{
//do something
}
int i = 100;
}
}
The declaration of int i = 100; is considered to be enclosing the for loop (regardless of whether it's not at the top of the method), so you cannot use the same name variable as one that appears in a block that contains your block.
This question already has answers here:
Cannot assign null to an implicitly-typed variable
(4 answers)
Closed 3 years ago.
I have an else block containing two for loops.
With the second for loop I am trying to create a set of objectYouCreate instances from a clean slate, as in if a set of instances was previously made, it was already successfully destroyed via the first for loop. So each time this code runs (in the Update method), it is creating an entirely new set of instances after wiping the previous set.
This is the (could be flawed) logic I came up with to do that, but I'm getting this error:
Error: "Cannot assign <null> to implicitly typed variable"
Can I receive help with how to best restructure this code logically and without errors. Thank you.
else{
var objectYouCreate = null; //gives the error
for (int i = 0; i < mesh.vertexCount; i++)
{
Destroy(objectYouCreate);
}
for (int i = 0; i < mesh.vertexCount; i++)
{
Vector3 position = mesh.vertices[i];
objectYouCreate = Instantiate(CubePrefab, position, transform.rotation);
}
}
__
edit:
By introducing usage of tags to my code... I was able to change the code so that the only var declaration happens inside a single for loop and is not null.
I'm also trying to utilize the tags for the Destroy portion, so that it does not just focus the same object but instead focuses all objects with the given tag upon instantiate. But this new code crashes Unity! If anyone has suggestions for optimization or a different method please let me know.
else
{
while (GameObject.FindWithTag("CubePFInst") != null) Destroy(GameObject.FindWithTag("CubePFInst"));
for (int i = 0; i < mesh.vertexCount; i++)
{
Vector3 position = mesh.vertices[i];
var cubeClone = Instantiate(CubePrefab, position, transform.rotation);
cubeClone.tag = "CubePFInst";
}
}
var was introduced for compile-time type-binding for anonymous types yet we can use var for primitive and custom types that are already known at design time. At runtime there's nothing like var, it is replaced by an actual type that is either a reference type or value type.
References:
var (C# Reference)
https://www.itorian.com/2015/04/initialize-var-with-null-or-empty-in-c.html
This question already has answers here:
How can I capture the value of an outer variable inside a lambda expression?
(4 answers)
Closed 6 years ago.
What is going on here? This loop most of the time just prints this:
10101010101010101010
sometimes this:
51010101010101010101
and when i debug it, it prints in order
0123456789
class Program
{
static void Main (string[] args)
{
for ( int i = 0; i < 10; i++)
{
Task.Run(( ) => Console.Write(i));
}
Console.Read();
}
}
If you have ReSharper installed it puts a little squiggle underneath the i:
with the note:
Access to modified closure
The JetBrains site gives this explanation:
This may appear to be correct but, in actual fact, only the last value of str variable will be used whenever any button is clicked. The reason for this is that foreach unrolls into a while loop, but the iteration variable is defined outside this loop. This means that by the time you show the message box, the value of str may have already been iterated to the last value in the strings collection.
(obviously their example uses a string not an int).
It "works" under debug because other things are going on and the code isn't being executed the same as it would in release.
The solution is to use a local variable:
for ( int i = 0; i < 10; i++)
{
int local = i;
Task.Run(( ) => Console.Write(local));
}
But even then it's not guaranteed to execute in the order you expect. I just tested this and got he result:
0436215897
So each value was processed, but in indeterminate order.
This question already has answers here:
Using the iterator variable of foreach loop in a lambda expression - why fails?
(3 answers)
Closed 8 years ago.
I got this piece of code,
delegate void Printer();
static void Main(string[] args)
{
List<Printer> printers = new List<Printer>();
for (int i = 0; i < 10; i++)
{
printers.Add(delegate { Console.WriteLine(i); });
}
foreach (Printer printer in printers)
{
printer();
}
Console.ReadLine();
}
Here the output is '10' for ten times.
The scope of i is with in the for loop. But while we retrieve in out side that we are still getting value from i.
How is it possible?
You have modified closure. Try this:
for (int i = 0; i < 10; i++)
{
int ii = i;
printers.Add(delegate { Console.WriteLine(ii); });
}
When you use in your anonymous method access the the variable in you local scope it creates closure.
The code in the delegate is not run until it is called, which happens in the second loop. It then refers to the i which was defined within the scope of the first loop, but with it's current value - and since the first loop has been completed already, i will be 10 each time.
I believe each of the delegates you create are given the same scope as the first loop, if that makes sense. This means that each i has it's delegate as it's scope, and since each delegate is defined within the scope of the first loop, each i will also have the loop as it's scope, even if the delegate logic is called outside that scope, as in your example.
Since i is valid throughout / across several iterations of the loop, it gets updated, and is always 10 by the time the delegates get called.
This explains why the following works as a fix:
for(int i = 0; i < 10; i++)
{
var localVar = i; // Only valid within a single iteration of the loop!
printers.Add(delegate { Console.WriteLine(localVar); });
}
Let's unroll the loop:
int i=0;
printers.Add(delegate { Console.WriteLine(i); })
i=1;
printers.Add(delegate { Console.WriteLine(i); })
...
i=10;
printers.Add(delegate { Console.WriteLine(i); })
As you can see the i variable is captured within the delegate, and the delegate itself is not run until the loop ends, and the variable has achieved the last value (10).
A simple workaround is to assign the loop variable to a local helper variable
for (int i = 0; i < 10; i++)
{
var index = i;
printers.Add(delegate { Console.WriteLine(index); });
}
As for the scope issue, any captured variables have their scope (and lifetime) extended. A variable used within a lambda/delegate will not be garbage collected until the delegate itself goes out of scope - which can be a problem for large objects. Specifically, section, 7.15.5.1 of the C# 5 Specification states:
When an outer variable is referenced by an anonymous function, the
outer variable is said to have been captured by the anonymous
function. Ordinarily, the lifetime of a local variable is limited to
execution of the block or statement with which it is associated
(§5.1.7). However, the lifetime of a captured outer variable is
extended at least until the delegate or expression tree created from
the anonymous function becomes eligible for garbage collection.
Each delegate is only invoked in the foreach, after the for loop. By this time, the variable i captured by the closure is already at its final value, viz 10. You can solve like so:
for (int i = 0; i < 10; i++)
{
var cache = i;
printers.Add(delegate { Console.WriteLine(cache); });
}
This question already has answers here:
C# variable scoping: 'x' cannot be declared in this scope because it would give a different meaning to 'x'
(3 answers)
Why does local variable inside foreach loop conflict with variable declared outside the loop?
(1 answer)
Closed 8 years ago.
In my mental model, counter variables defined inside for become private because it cannot be access from outside as follows.
for (int x = 0; x < 2; x++) ;
//Console.WriteLine(x); x does not exist in the current context
My confusion occurs when I declared the same variable as follows,
for (int x = 0; x < 2; x++) ;
//Console.WriteLine(x); x does not exist in the current context, but why cannot I declare
//int x = 1;
Why does the compiler disallow me to declare a variable with the same name as another inaccessible variable? It does not make sense to me. :-)
To make more confusing compare it with
{
int x = 1;
}
{
int x = 2;
}
which is allowed by the compiler. But both below are not allowed.
static void Foo()
{
int x = 1;
{ int x = 2; }
}
static void Bar()
{
{ int x = 2; }
int x = 3;
}
This behaviour is covered in section 3.7 of the language spec. It says, “The scope of a local variable declared in a local-variable-declaration (8.5.1) is the block in the which the declaration occurs”.
The scope of x is therefore the entire function, and that means that the use in the for loop is a re=use, and therefore is not allowed.
This behavior is inteded to make incorrect re-use of variable names (such as in a cut and paste) less likely.
aleroot already gave the answer to your first part. I want to answer second part of your question.
{
int x = 1;
}
{
int x = 2;
}
which is allowed by the compiler.
Yes, because there is no local variable x in the same scope or any nested scope. For example;
static void Main()
{
int x;
{
int y;
int x; // Error - x already defined in same scope or parrent scope.
}
{
int y; // OK - there is no y in the same scope or any nested scope.
}
Console.Write (y); // Error - there is no y in same scope of any parrent scope.
}
Couse for loop almost declared x varible inside it, so u cant redeclared x varible, as can exists only one declaration in scope.