c# value sent to Func not peristant, c# IIFE equivalent - c#

This loop is executed
CoordPosition = new Func<string, int>[3];
for (int i = 0; i < CoordPosition.Length; i++)
{
CoordPosition[i] = (x => CapStringNumber(x, i));
}
When the method CapStringNumber is later executed by the funcs its second parameter has the value 3 for the entire array. I want it to be 0, 1, 2.
The following works:
CoordPosition = new Func<string, int>[3];
for (int i = 0; i < CoordPosition.Length; i++)
{
var localVariable = i;
CoordPosition[i] = (x => CapStringNumber(x, localVariable));
}
What is the proper way to achieve the effect I want? Making that localVariable seems a bit un-maintainable. I don't know javaScript but i'm told that 'IIFE' is a relevant javaScript term for this.

Related

Adding method to delegate changes iteration in "for" loop - C# issue? [duplicate]

This question already has answers here:
How to tell a lambda function to capture a copy instead of a reference in C#?
(4 answers)
Closed 5 years ago.
I've faced some issue with C# code. Adding method to delegate in "for" loop increments "i" by one., so "for(int i = 0, i < x ; i++)" must be change to "for(int i = -1, i < x-1; i++)" to work correctly. Why is that?
Code below throws an IndexOutOfRangeException
string[] names = new string[] { "John", "Madeline", "Jack", "Gabby" };
Action showNameDelegate = null;
for (int i = 0; i < names.Length; i++)
{
showNameDelegate += () => global::System.Console.WriteLine(names[i]);
}
foreach (Action showName in showNameDelegate.GetInvocationList())
{
showName();
}
Right code is (look at iterator "i" which starts from -1 but "names[-1]" does not exist):
string[] names = new string[] { "John", "Madeline", "Jack", "Gabby" };
Action showNameDelegate = null;
for (int i = -1; i < names.Length - 1; i++)
{
showNameDelegate += () => global::System.Console.WriteLine(names[i]);
}
foreach (Action showName in showNameDelegate.GetInvocationList())
{
showName();
}
This answer is correct (by Ed Plunkett):
Each delegate references the variable i. They all reference the variable, so when they execute, they'll get whatever value it has right then. The delegates are executed after the for loop completes. At that point, i is equal to names.Length. Make a local copy of i in the body of the loop -- or use a foreach loop, which automatically fixes this issue.
You should change your code like this;
for (int i = -1; i < names.Length - 1; i++)
{
string name = names[i];
showNameDelegate += () => global::System.Console.WriteLine(name);
}
Or you can try to use foreach.

C# threading passing integer argument passes bad number

Good day to everyone.
Today I made up a school project with one thing bothering me.
My problem is, that I am passing argument to Thread function and when I print it to console via Console.WriteLine, it shows bad numbers.
for (i = 0; i < 10; i++) autari[i] = new Thread(() => autar(i));
for (i = 0; i < 10; i++) motorkari[i] = new Thread(() => motorkar(i + 10));
When I start them in same cycles, their functions do this:
static void motorkar(int id)
{
Console.WriteLine("motorkar {0}", id);
...
It is not the order problem, but when I pass for example 0. Visual studio in Debug writes to console number 2 and without Debug it writes 1.
What can be the problem? I know that I can solve this by setting string name, but I am confused with this.
This is due to the compiler creating you a closure under the hood. If you change the code around to the below you should get your expected output
for (i = 0; i < 10; i++)
{
var local = i;
autari[i] = new Thread(() => autar(local))
}
for (i = 0; i < 10; i++)
{
var local = i + 10;
motorkari[i] = new Thread(() => motorkar(local))
}

Is there a compact way to find the indices of an occurrence of an element in a 2-D array?

Example:
Say I have
var arr = new int[][] {
{ 1, 9, 4 },
{ 2, 4, 4 },
{ 3, 0, 5 }
};
and say I want the indices of 3. So I want a method that does the equivalent of
Tuple<int,int> indices;
for(int i = 0; i < arr.Length; ++i)
for(int j = 0; j < arr[i].Length; ++j)
if(arr[i][j] == 3)
return new Tuple<int,int>() { i, j }
ideally without having to write any extension methods and ideally in a way that is compact and efficient.
You can do this in LINQ in a "compact" manner - but as the comments suggest, a regular loop will trounce this for efficiency:
var indexes = arr.Select((a, x) => a.Select((v, y) => new { X = x, Y = y })
.Where(z => arr[z.X][z.Y] == 3)).SelectMany(x => x);
Even using LINQ, you still have to traverse the entire collection and build up the indexes (into an anonymous type here) and determine if they meet your criteria (and then flatten the result using SelectMany).
Also note this will return all instances, to get the first occurance simply throw a .First() on the end.
I'd strongly recommend a static helper or extension method in this case:

How to optimize code that changes a value deeply nested in an object graph

Below is a crude for-loop to illustrate what I need to do.
Basically, if there are any 'Variable' objects with property 'Name' containing the text "TCC#", then I want to change the 'Type' property (not the .Net type) to 'VariableType.Text'.
The code is going to run over 4800 ParsedCard variables and currently takes a stupid amount of time (about 10 minutes) to simply iterate through the list and write a line to the Debug console.
ParsedCard has
IEnumerable functions which have
IEnumerable groups which have
ParseResults which have
IEnumerable variables
This is such a simple problem but I've tried all sorts of variations using LINQ but can't find anything that performs well (less than 10 seconds).
private void AdjustTCCVariables(IList<ParsedCard> parsedCards)
{
for (var i = 0; i < parsedCards.Count; i++)
{
var parsedCard = parsedCards[i];
for (var j = 0; j < parsedCard.Functions.Count(); j++)
{
var function = parsedCard.Functions.ToList()[j];
for (var k = 0; k < function.Groups.Count(); k++)
{
var group = function.Groups.ToList()[k];
for (var l = 0; l < group.ParseResult.Variables.Count(); l++)
{
var variable = group.ParseResult.Variables.ToList()[l];
if (variable.Name.Contains("TCC#"))
{
//variable.Type = VariableType.Text;
Debug.WriteLine($"Need to change variable at [{i}][{j}][{k}][{l}]");
}
}
}
}
}
}
I've tried with this LINQ but it doesn't actually change the 'variable.Type' of the input list (I suspect because it creates a new copy of the objects in memory and the assignment isn't actually affected the 'parsedCards' IEnumerable at all:
private void AdjustTCCVariables(IEnumerable<ParsedCard> parsedCards)
{
var targetVariables =
parsedCards.SelectMany(x => x.Functions.SelectMany(z => z.Groups))
.SelectMany(x => x.ParseResult.Variables.Where(v => v.Name.Contains("TCC#")));
;
foreach (var variable in targetVariables)
{
variable.Type = VariableType.Text;
}
}
As mentioned, the bottleneck in your iterations is the .ToList() calls.
Since you mention that you only want to edit the variable.Type property, I would solve this like this.
var variables = from parsedCard in parsedCards
from function in parsedCard.Functions
from group in function.Groups
from variable in group.ParseResult.Variables
where variable.Name.Contains("TCC#")
select variable;
foreach (var variable in variables) {
variable.Type = VariableType.Text;
}
You don't need to know anything other than the variable objects that need changing, you don't need all the indexes and all the other variables. Just select what you need to know, and change it.
This way you will not know the indexes, so your Debug.WriteLine(...); line won't work.
Without knowing what the defintion of the classes , here is some tips.
Remove toList, dont count on the iteration (for statement)
int numberOf = parsedCards.Count
for (var i = 0; i < numberOf; i++)
{
//var parsedCard = parsedCards[i];
int noOf2 = parsedCard[i].Functions.Count()
for (var j = 0; j < noOf2; j++)
{
var function = parsedCard[i].Functions[j];
int = function.Groups.Count();
for (var k = 0; k < noOfGroups; k++)
{
var group = function.Groups[k];
int noOfVars = group.ParseResult.Variables.Count();
for (var l = 0; l < noOfVars; l++)
{
var variable = group.ParseResult.Variables[l];
if (variable.Name.Contains("TCC#"))
{
//variable.Type = VariableType.Text;
Debug.WriteLine($"Need to change variable at [{i}][{j}][{k}][{l}]");
}
}
}
}
}

Index was outside the bounds of array when using List<Func<T,object>>

I have a class like this:
class MyClass { public object[] Values; }
Somewhere else I'm using it:
MyClass myInstance = new MyClass() {Values = new object[]{"S", 5, true}};
List<Func<MyClass, object>> maps = new List<Func<MyClass, object>>();
for (int i = 0; i < myInstance.Values.Length ; i++)
{
maps.Add(obj => obj.Values[i]);
}
var result = maps[0](myInstance); //Exception: Index outside the bounds of the array
I thought it will returns S, but it throw exception. Any idea what is going on?
To see what's going on, change your lambda to maps.Add(obj => i);.
With that change result will be 3, and that's why you're getting IndexOutOfBoundException exception: you're trying to get myInstance[3] which does not exist.
To make it work, add local int variable within your loop and use that one as index instead of loop counter i:
for (int i = 0; i < myInstance.Values.Length; i++)
{
int j = i;
maps.Add(obj => obj.Values[j]);
}

Categories