C# Referencing the value of a variable [duplicate] - c#

This question already has an answer here:
Is it possible to instantiate objects with variable names, or access variable names at runtime?
(1 answer)
Closed 1 year ago.
I'm having difficulty understanding how I can reference the return value of a variable to create another in C#.
string name = Console.ReadLine();
List<Thing> name = new List<Thing>();
For example, user inputs "Cats" and thus a new list Cats is created.
Or in this scenario:
for (int i = 0; i < 5; i++)
{
List<Thing> (animal + i) = new List<Thing>();
}
Where the lists created becomes animal0, animal1, animal2... etc.
Thank you

You cannot do that in C# at least not naturally.
Variable are determined at the compile time.
Value you are talking about (Cats, animal0, ...) are determined at the runtime, when the code is really running, which occurs after the compilation. So those values cannot become variable names.

You cannot create variables dynamically at runtime, so every variable you would like to use needs to be declared on compile time. Nevertheless, a List<Thing> can hold multiple instances of a Thing at the same time, representing - in your sense - multiple variables.
For example:
var things = new List<Thing>();
for (int i = 0; i < 5; i++) {
things.Add(new Cat()); // if Cat derives from Thing
}
// access the list items by index
Console.WriteLine(thing[0]);
Console.WriteLine(thing[1]);
...

Related

Why These two c# scripts give different results? [duplicate]

This question already has answers here:
Regarding local variable passing in Thread
(2 answers)
Closed 2 years ago.
I'm working on a big list of buttons and trying to AddListener() for every Button on this list using a quick way
the first way is
btn[0] = CHbutt[0].GetComponent<Button>(); btn[0].onClick.AddListener(delegate { CH(0); });
btn[1] = CHbutt[1].GetComponent<Button>(); btn[1].onClick.AddListener(delegate { CH(1); });
btn[2] = CHbutt[2].GetComponent<Button>(); btn[2].onClick.AddListener(delegate { CH(2); });
btn[3] = CHbutt[3].GetComponent<Button>(); btn[3].onClick.AddListener(delegate { CH(3); });
and it works very well, and AddListener() to all Buttons in btn[];
but a lot of lines...
the second way
for (int i = 0; i < CHmatt.Count; i++)
{
btn[i] = CHbutt[i].GetComponent<Button>(); btn[i].onClick.AddListener(delegate { CH(i); });
}
but this one is not working, this one AddListener() to only the last button btn[0]
I'm very curious about the difference between these two scripts.
It's a capturing issue. Change the code as follows, to avoid capturing i:
for (int i = 0; i < CHmatt.Count; i++)
{
var ii = i;
btn[i] = CHbutt[i].GetComponent<Button>();
btn[i].onClick.AddListener(delegate { CH(ii); });
}
What is being passed into AddListener function is a delegate method; however, since you're passing in a loop iteration variable i, the context is captured, and i is actually referenced. As your loop advances, the value of i changes for all captures, therefore making this approach "not work".
By introducing a local copy of i (the name is not material here, I called it ii), which goes out of scope on each loop iteration, the capture of i is avoided, and the actual value of ii is passed to the delegate method (technically, captured, but it's a copy of i for each loop iteration, and therefore does not change as i changes.)

Catching value of the concatenated variable

My environment is: W7 Ultimate 64 bits, VS2010 Ultimate, C#, WinForm, target XP and W7.
With the help of #dasblinkenlight, the concatenation on the for loop was very good.
I feel we are making great progress.
As you ca see, we are putting into the array sMntHour[d,h] the string "csv_001_01" if d=1 and h=1 and so on.
This csv_001_01, csv_001_02,.. ; are variables that contains an integer value.
csv_001_01=5111;
csv_001_02=236; // This is a sample, because has 365 days in normal year
// and 366 days in leaf year. "csv_day_hour"
Directly we could do this:
sMntHour[d,h] = csv_001_01.ToString(); // d is day and h is hour
sMntHour[d,h] = csv_001_02.ToString();
As we put the value of this concatenated variable in the array and not the name of the variables?
for(int d=1;d<=365;d++) //I'll put the code to not leap years.
{
for(int h=1; h<=24; h++)
{
sMntHour[d,h] = string.Format("csv_{0:000}_{1:00}", d, h)
}
}
If I understand what you mean, you have all the variable names and now you want to get their values.
You could do this using Reflection and you can create a dictionary where keys are the variable names and the values are the actual values. It is really hard to help without seeing how these variables are declared, are they fields / properties ? are the private, static ? etc... But something like this should work, in theory:
var type = this.GetType();
var values = sMntHour.OfType<string>()
.ToDictionary(
x => x,
x => (int)type.GetField(x).GetValue(this));
Then you can access the values using values["variable_name"]
Or if you don't want this, instead if you want to access them using index like [d,h] as mentioned in comments, do not store the variable names in the first place instead store the values in your array:
var type = this.GetType();
for(int d=1;d<=365;d++)
{
for(int h=1; h<=24; h++)
{
var name = string.Format("csv_{0:000}_{1:00}", d, h);
sMntHour[d,h] = (int)type.GetField(name).GetValue(this);
}
}
Ofcourse you need to change the type of sMntHour, in order to make it work.

Why does this output 333 not 0112 at Array.ForEach? [duplicate]

This question already has answers here:
Is there a reason for C#'s reuse of the variable in a foreach?
(4 answers)
Closed 8 years ago.
Why the below code ouput 333 not 012?
I think the code is so simple and I check and check and double check, triple check, can not get answer yet. Any one can help me?
Action[] tmp = new Action[3];
for (int i = 0; i < tmp.Length; i++)
{
tmp[i] = () => Console.WriteLine(i);
}
Array.ForEach(tmp, m => m());
Console.Read();
You should change your code to:
Action[] tmp = new Action[3];
for (int i = 0; i < tmp.Length; i++)
{
int j = i;
tmp[i] = () => Console.WriteLine(j);
}
Array.ForEach(tmp, m => m());
Console.Read();
The reason is closure is nest
More detailed information please see those links:
Is there a reason for C#'s reuse of the variable in a foreach?
http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/
This occurs because there is only one i variable in the original code as for does not introduce a new variable "each loop" and the same variable is closed over in all the closures! As such, the same (i) variable is assigned the last value (3) before any of the functions are executed after the loop.
Compare with the following code which ensures a new variable to bind in each closure (this is one rare case where I use underscores for a local variable to show "something funny" is happening):
for (int _i = 0; _i < tmp.Length; _i++)
{
int i = _i; // NEW/fresh variable, i, introduced each loop
tmp[i] = () => Console.WriteLine(i);
}
This behavior (and complaints against) is discussed in detail in Is there a reason for C#'s reuse of the variable in a foreach? - for and foreach have this same "issue" in C#4 and before, which is "fixed" for foreach in C#5.
I think it is fair to say that all regret that decision. This is one of the worst "gotchas" in C#, and we are going to take the breaking change to fix it. In C# 5 the foreach loop variable will be logically inside the body of the loop, and therefore closures will get a fresh copy every time. - Eric Lippert

Name a list with a combination of previously defined variables in C#?

I'm trying to create a method that names a variable based on a specific set of other variables. For example, I want to create series of Lists (i.e., List1, List2, List3) by named according to two variables. For example:
string l = "List"
int += 1
Such that as I cycled through the code using a foreach loop it would name each List consecutively. Any ideas? I've only gotten this much "correct" so far and its not much:
public static string[] ListRenamer(List<string> list, int num)
{
string x = list.ToString();
string y = num.ToString();
string[] z = new string[1];
return z;
}
I would consider a Dictionary<string,List<string>> instead of separate lists here.
You can then name the keys according to your convention, and it can be done dynamically at runtime.
It is not possible to rename c# variables at runtime since c# is a static language

Why c# compiler generates a compile error? [duplicate]

This question already has answers here:
Why can't a duplicate variable name be declared in a nested local scope?
(9 answers)
Closed 9 years ago.
I have following code
using(some code)
{
var b = ....
}
var b = ...
Erorr: A local variable named 'b' cannot be declared in this scope because it would give a different meaning to 'b', which is already used in a 'child' scope to denote something else
Ok, editing
using(some code)
{
var b = ....
}
b = ...
Error: The name 'b' does not exist in the current context
"The local variable declaration space of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block." Variable Scopes, MSDN
can you do this?
for (int i = 0; i < 10; i++)
{
int j = 1;
}
int j = 2;
The answer is NO which means it pretty much consistent everywhere. Now it begs the question why. Answer to this question is It is illegal to have two local variables of the same name in the same local variable declaration space or nested local variable declaration spaces. And in the above case declaration of J is within the same nested scope.
The correct code should be:
var b = something;
using(some code)
{
b = smth;
}
b = smth;
You cannot use a variable declared inside a block ({}) outside of that block.

Categories