Anonymous c# delegate within a loop - c#

Hi all i am trying to write and anonymous delegate. as the integer variable is shared among the delegate i need it to be the local instance of every delegate such that rs[0] always gets nics[0], rs[1] always gets nics[1] and so on... how will i achieve this.
for (int i = 0; i < nics.Count; i++)
{
rs[i] = new RollingSeries(monitor, new RollingSeries.NextValueDelegate(delegate()
{
return GetNetworkUtilization(nics[i]);
}));
}
Abdul khaliq

Make a local copy of i:
for (int i = 0; i < nics.Count; i++)
{
int j = i;
rs[i] = new RollingSeries(monitor, new RollingSeries.NextValueDelegate(delegate()
{
return GetNetworkUtilization(nics[j]);
}));
}
The Beauty of Closures

Use a local to get a different value per iteration
for (int i = 0; i < nics.Count; i++)
{
int localI = i;
rs[i] = new RollingSeries(monitor, new RollingSeries.NextValueDelegate(delegate()
{
return GetNetworkUtilization(nics[localI]);
}));
}

Put int j = i inside your loop and refer to j within the lambda expression.
If you are curious about why this happens, here is an MSDN blog entry containing a detailed technical explanation: Closing over the loop variable considered harmful

Related

How can I figure out if one List has different value than the other List

I have two special List(defaultGeometry,changedGeometry) and I have one another method (AreCoordinatesEqual) which can compare coordinates and return boolean.
for (int i = 0; i < defaultGeometry.Count; i++)
{
for (int j = 0; j < changedGeometry.Count; j++)
{
if (!AreCoordinatesEqual(defaultGeometry[i], changedGeometry[i]))
{
return false;
}
}
}
My question is; If, changedGeometry has even one different coordinate(or lets say value) from defaultGeometry then I should return false. Basically I want to match every changedGeometry coordinates with every defaultGeometry coordinates so that I will realize If any foreign value changedGeometry has. Please note that; defaultGeometry can have different values it's ok. So I tried some contain methods but I would like to use my method(AreCoordinatesEqual) in that case and nested loops looks the best solution. But any other ways are appreciated. I would be grateful for any help at this point. Thank you
Linq appraoch with Zip() and All()
return defaultGeometry.Zip(changedGeometry,(d,c) => AreCoordinatesEqual(d,c)).All(x => x);
... or you just remove the second for loop in your own appraoch and add return true; at the end
I think 5th row's changedGeometry number is wrong
for (int i = 0; i < defaultGeometry.Count; i++)
{
for (int j = 0; j < changedGeometry.Count; j++)
{
if (!AreCoordinatesEqual(defaultGeometry[i], changedGeometry[**j**]))
{
return false;
}
}
}
I would recommand to just use the .Except() method from LINQ.
The only condition is to make sure your entity implements the IEqualityComparer interface
Here is a sample and its result with Points (which act as your coordinates):
using System.Drawing;
var oldPoints = new List<Point>()
{
new Point(0, 0),
new Point(1,1),
new Point(2,2),
new Point(3,3),
new Point(4,4),
};
var newPoints = new List<Point>()
{
new Point(0, 0),
new Point(1,1),
new Point(-2,-2),
new Point(-3,-3),
new Point(-4,-4),
};
var changedPoints = newPoints.Except(oldPoints);
var changedPointsCount = changedPoints.Count();
Console.WriteLine($"Number of point changed: {changedPointsCount}");
if(changedPointsCount > 0)
{
foreach(var changedPoint in changedPoints)
{
Console.WriteLine($"New point detected: X={changedPoint.X} # Y={changedPoint.Y}");
}
}
Output:
Number of point changed: 3
New point detected: X=-2 # Y=-2
New point detected: X=-3 # Y=-3
New point detected: X=-4 # Y=-4

Can I have an if statement change what variable is accessed in a loop

Hey I'm in a situation where I have a for loop that does some stuff and I want to make a line of code either call a function passing in an array indexed by the for loops index, or run a single (not array) variable for every call of that function, I know I could do that by putting an if statement inside the for loop but i'd be repeating the same if statement over and over getting the same result. So is there a way good way I can run the if statement before the for loop and the result of that if statement run the same for loop but that one call passes in the array or the variable?
Code Example
for (int i = 0; i < CurrentVerticalList.Count; i++)
{
GuiGeneral CGroup = CurrentVerticalList[i];
CGroup.ResizeUsingStandard(ForcedResize[i]); //I want the condition before the for
//loop to have ForcedResize[i] here if
//true and another variable here of the
//same type but not an array if false.
for (int j = 0; j < 2; j++)
{
GlobalListIndex[j]++;
}
CGroup.MoveElementTo(CCoord, false);
CCoord.y += CGroup.ElementRect.WidthHeight.y;
}
Here you go, moving your condition check out of your for loop:
Func<int, double> GetResizeFromForcedResize = (index => ForcedResize[index]);
Func<int, double> GetResizeFromVariable = (index => fixVariable);
var GetResizeValue = condition? GetResizeFromForcedResize : GetResizeFromVariable;
for (int i = 0; i < CurrentVerticalList.Count; i++)
{
GuiGeneral CGroup = CurrentVerticalList[i];
CGroup.ResizeUsingStandard(GetResizeValue(i));
for (int j = 0; j < 2; j++)
{
GlobalListIndex[j]++;
}
CGroup.MoveElementTo(CCoord, false);
CCoord.y += CGroup.ElementRect.WidthHeight.y;
}
Edit: Wanted to let you know that the other answers here are still doing a check at every iteration, but not this one.
Eh, hard to understand the question to me but i recon what you want is something along these lines, could've helped with more types supplied, but you could make the intend achievable using a local function:
ForcedResizeArrayType other = new object(); //TODO: Define return type
bool condition = ResolveCondition(); //TODO: Define condition to be true or false
ForcedResizeArrayType GetOneOr(int i, bool condition,
ForcedResizeArrayType[] forcedResizeArray)
{
return condition ? forcedResizeArray[i] : other;
}
for (int i = 0; i < CurrentVerticalList.Count; i++)
{
CGroup.ResizeUsingStandard(GetOneOr(i, condition, ForcedResize));
}
It varies from week to week if i love or hate those local functions, but they have uses

How to prevent "index" to updated itself in array of Action

When I add to array of Actions with a for loop a delegate the I is updated across the array. How to prevent that from happening?
I have tried assigning the "I" to an integer before adding that works.
Action[] actions = new Action[100];
for (int i = 0;i< actions.Length; i++)
{
actions[i] = () => Console.WriteLine("Hello"+ i);
}
"I" in each Action in Action[] is 100;
Why is that?
because they are all assigned to the same local variable "int i"
and after the loop end "i" is 100
Action[] actions = new Action[100];
for (int i = 0;i< actions.Length; i++)
{
int a = i;
actions[i] = () => Console.WriteLine("Hello"+ a);
}
after declare int a = i , you have respective a for each actions
Here and Here are good explanations on similar question. Here is also good explanation on C# closures by Jon Skeet.
In for loop there is only one single variable i used. That's why later on when you are executing actions, they all reference to same value i=100. If action need to use actual value of the current i you have to capture a copy of it and store copy to action.
for (int i = 0;i< actions.Length; i++)
{
int copy = i;
actions[i] = () => Console.WriteLine("Hello"+ copy);
}

How Add A String To Variables,Methods,Threads,... Names

Below is a simple example:
int Parallel_Count = int.Parse(nudParallelCount.Text);
for (int i = 1; i <= Parallel_Count; i++)
{
Thread string.Format("Thread_{0}", i) = new Thread(new ThreadStart(string.Format("Thread_{0}_Inside", i) ));
string.Format("Thread_{0}", i).Start();
}
As you see I did not use regular names for thread names and their entries and my codes have error because of them.
I want to add a counter (as a string) to thread names and thread entries names.
EDIT
One of my entries is like this :
public void Thread_1_Inside()
{
bloblobloblo -> i've created this expression by myself :)
}
You are looking for a container like an array or a list. Please make sure you understand those structures before you go into threading because they are pretty basic constructs and threading is tough stuff.
int Parallel_Count = int.Parse(nudParallelCount.Text);
Thread[] threads = new Thread[Parallel_Count];
for (int i = 0; i < Parallel_Count; i++)
{
threads[i] = new Thread(/*fill thread start here*/);
threads[i].Start();
}

Pass non reference value to Task

I often get strange resulst when passing int variables to tasks such as in this example:
List<List<object>> ListToProcess = new List<List<object>>();
// place some lists in list to process
foreach (var temp in Foo)
ListToProcess.Add(temp);
foreach (var tempArray in ListToProcess)
{
// initialize each list in ListToProcess
}
int numberOfChunks = ListToProcess.Count;
Task[] tasks = new Task[numberOfChunks];
for (int counter = 0; counter < numberOfChunks; counter++)
{
tasks[counter] = Task.Factory.StartNew(() =>
{
// counter is always = 5 why? <---------------------------
var t = ListToProcess[counter];
});
}
How can I solve this problem?
This is known as a closure. You are not using the value of the variable, you are using the variable itself. When the code executes, it uses the value at the time of execution, not the value when the Task was defined.
To fix this issue, I believe you would do something like this:
for (int counter = 0; counter < numberOfChunks; counter++)
{
int cur = counter;
tasks[counter] = Task.Factory.StartNew(() =>
{
// counter is always = 5 why? <---------------------------
var t = ListToProcess[cur];
});
}
There is no guarantee as to when the 'counter' variable in the Action block of StartNew will be accessed. What is likely to happen is that all 5 values are looped through, and the tasks are created, then the tasks are scheduled to run.
When they do run, the following is executed:
var t = ListToProcess[counter];
But at this stage count is already equal to 5.
Perhaps you should look at parallel collections?
ListToProcess.AsParallel().ForAll(list => dosomething(list));
There are many other options around this area.
for (int counter = 0; counter < numberOfChunks; counter++)
{
var referenceVariable = new{val=counter};
tasks[counter] = Task.Factory.StartNew(() =>
{
var t = ListToProcess[referenceVariable.val];
});
}
Since variables are captured, you can solve this by redeclaring a new variable in each loop.
for (int counter = 0; counter < numberOfChunks; counter++)
{
int localCounter = counter;
tasks[localCounter] = Task.Factory.StartNew(() =>
{
// counter is always = 5 why? <---------------------------
var t = ListToProcess[localCounter];
});
}

Categories

Resources