c# create a .forEach() Method using actions [duplicate] - c#

This question already has answers here:
Why does assignment to parameter not change object?
(4 answers)
Closed 8 months ago.
I'm trying to create a method that loops through an array and executes some actions I wrote with a lambda expression. Somehow I don't think I understood how to use actions correctly because my code just results in a bunch of "null" objects.
Does somebody know what I am doing wrong?
public void forEach(Action<Neuron> action)
{
for(int i = 0; i < this.Neurons.Length; i++)
{
action(this.Neurons[i]);
}
}
public void CreateNeurons(int AmountOfNeurons)
{
this.Neurons = new Neuron[AmountOfNeurons];
this.forEach(x => x = new Neuron(AmountOfNeurons));
}

In your delegate, setting x = ... only changes the value of that local parameter: it does nothing to the array itself. You would end up with the same problem if you used a for loop like this:
var a = new[] { 1, 2, 3};
for (int i = 0; i < a.Length; i++)
{
var x = a[i];
x = 5; // this does nothing to `a[i]`
}
Notably, a foreach loop would warn you if you tried to do this:
foreach (var x in a)
{
x = 5; // CS1656: Cannot assign to 'x' because it is a foreach variable.
}
This supports Dai's comment: you really shouldn't be defining your own forEach method. There are plenty of better, more idiomatic ways to do anything you'd want to do with a method like this. A foreach construct would have told you exactly what you were doing wrong, for example. And creating an array with a bunch of items is typically simpler with LINQ:
this.Neurons = Enumerable.Range(0, AmountOfNeurons)
.Select(_ => new Neuron(AmountOfNeurons))
.ToArray();

Related

Why struct properties cannot be changed if they are in a list? [duplicate]

This question already has answers here:
In C#, why can't I modify the member of a value type instance in a foreach loop?
(8 answers)
Closed 3 years ago.
Please consider the following code:
public class Program {
public struct A
{
public int Prop {get;set;}
}
public static void Main()
{
var obj = new A();
obj.Prop = 10;
var list = new List<A>(){obj};
foreach(var l in list) {
l.Prop = 20; //here I'm getting compile time error "Cannot modify members of 'l' because it is a 'foreach iteration variable'"
}
}
}
So my question is: why struct properties cannot be assigned while iterating over a list of structs?
Please note that even when iterating with simple for like this:
for (int i=0; i<list.Count(); ++i)
list[i].Prop = 20;
I'm still getting compile time error...
You cannot modify collection over which you are iterating with foreach.
Instead you should use for loop, which allows that:
for(int i = 0; i < list.Length; i++)
{
list[i].Prop = 200;
}
You can refer to this question: Why can't we assign a foreach iteration variable, whereas we can completely modify it with an accessor?

ForEach with index in C# [duplicate]

This question already has answers here:
List<T>.ForEach with index
(12 answers)
Closed 4 years ago.
I'm need to call function from ForEach in Linq, and I need to send a string parameter and the Index from the ForEach
List<string> listString= new List<string>();
listString.ForEach((str, i) => { Func(str, i) , i++});
private ResponseBase Func(string s,int i)
{
You could try something like this:
var responses = listString.Select((value, index) => Func(value, index)).ToList();
The above for each item in listString would call the method you have defined. The results of all calls would be stored in a list and you could access them by using the corresponding index.
I'm a big fan of LINQ. Really.
But in this cases, when you are accessing an already existing List, I would go for an old fashioned for loop.
for(var i = 0; i < listString.Count; i++)
Func(listString[i], i);
It's not longer, it's far more efficient (it's probably not a problem, but let's remember this), and it just gets the job done.
You can introduce a variable and then increment it:
List<String> values = new List<String>();
int indexTracker = 0;
values.ForEach(x=> { Func(x, indexTracker++); });
Or you can write the following extension method:
public static void ForEach<T>(this List<T> input, Action<T, int> action)
{
for(int i = 0; i < input.Count; i++)
{
action(input[i], i);
}
}
and then use it like
values.ForEach((x,i)=> Func(x, i));

Reversing an ienumerable of lambda functions

I have created an ienumerable of lambda functions using this function
static IEnumerable<Func<int>> MakeEnumerator(int[] values)
{
for (int a = 0; a < values.Length; a++)
{
yield return () => Values[a];
}
}
I cannot then reverse this using LINQ or convert into an array without all the values becoming the last function.
Example code (note this just demonstrates the problem it is not the code in the application):
int[] start = {1,2,3};
IEnumerable<Func<int>> end = MakeEnumerator(start).Reverse<Func<int>>();
foreach (Func<int> i in end)
{
Console.WriteLine(i());
}
I think the problem is in the MakeEnumerator function. How would I modify this to make it work or go about writing a working replacement reverse function.
The problem is that you're capturing the loop variable. All of your delegates are capturing the same variable, so they'll always see the latest value of a... which will be values.Length + 1 by the time you're executing the delegates, in your use cases. You can simply copy it instead:
for (int a = 0; a < values.Length; a++)
{
int copy = a;
yield return () => Values[copy];
}
Alternatively (and preferrably IMO) use a foreach loop, which currently requires the same workaround:
foreach (int value in values)
{
int copy = value;
yield return () => copy;
}
Or better yet:
return values.Select(x => (Func<int>)(() => x));
Or:
Func<int, Func<int>> projection = x => () => x;
return values.Select(projection);
See Eric Lippert's blog post "Closing over the loop variable considered harmful" for more information. Note that the behaviour of foreach may well be changing for C# 4.5.
All of your lambda expressions are sharing the same a variable.
Since you're only calling them after the loop finishes, a is always 3.
You need to give each one its own variable:
for (int dontUse = 0; dontUse < values.Length; dontUse++)
{
int a = dontUse;
yield return () => Values[a];
}
In this code, each lambda expression gets its own a variable (since it's scoped inside the loop), and these separate variables never change.

For loop goes out of range [duplicate]

This question already has answers here:
Captured variable in a loop in C#
(10 answers)
Closed 11 days ago.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.StartTasks();
}
}
class MyClass
{
int[] arr;
public void StartTasks()
{
arr = new int[2];
arr[0] = 100;
arr[1] = 101;
for (int i = 0; i < 2; i++)
{
Task.Factory.StartNew(() => WorkerMethod(arr[i])); // IndexOutOfRangeException: i==2!!!
}
}
void WorkerMethod(int i)
{
}
}
}
It seems that i++ gets executed one more time before the loop iteration is finished. Why do I get the IndexOutOfRangeException?
You are closing over loop variable. When it's time for WorkerMethod to get called, i can have the value of two, not the value of 0 or 1.
When you use closures it's important to understand that you are not using the value that the variable has at the moment, you use the variable itself. So if you create lambdas in loop like so:
for(int i = 0; i < 2; i++) {
actions[i] = () => { Console.WriteLine(i) };
}
and later execute the actions, they all will print "2", because that's what the value of i is at the moment.
Introducing a local variable inside the loop will solve your problem:
for (int i = 0; i < 2; i++)
{
int index = i;
Task.Factory.StartNew(() => WorkerMethod(arr[index]));
}
<Resharper plug> That's one more reason to try Resharper - it gives a lot of warnings that help you catch the bugs like this one early. "Closing over a loop variable" is amongst them </Resharper plug>
The reason is that you are using a loop variable inside a parallel task. Because tasks can execute concurrently the value of the loop variable may be different to the value it had when you started the task.
You started the task inside the loop. By the time the task comes to querying the loop variable the loop has ended becuase the variable i is now beyond the stop point.
That is:
i = 2 and the loop exits.
The task uses variable i (which is now 2)
You should use Parallel.For to perform a loop body in parallel. Here is an example of how to use Parallel.For
Alternativly, if you want to maintain you current strucuture, you can make a copy of i into a loop local variable and the loop local copy will maintain its value into the parallel task.
e.g.
for (int i = 0; i < 2; i++)
{
int localIndex = i;
Task.Factory.StartNew(() => WorkerMethod(arr[localIndex]));
}
Using foreach does not throw:
foreach (var i in arr)
{
Task.Factory.StartNew(() => WorkerMethod(i));
}
But is doesn't work either:
101
101
It executes WorkerMethod with the last entry in the array. Why is nicely explained in the other answers.
This does work:
Parallel.ForEach(arr,
item => Task.Factory.StartNew(() => WorkerMethod(item))
);
Note
This actually is my first hands-on experience with System.Threading.Tasks. I found this question, my naive answer and especially some of the other answers useful for my personal learning experience. I'll leave my answer up here because it might be useful for others.

Transform a delegate to a Expression Tree

I wonder if you can create and modify a Expression Tree out of a existing delegate.
Kinda like
public void Foo() {
Console.WriteLine(1000);
}
....
Expression exp = Foo.GetExpression();
//Now do something what changes 1000 to 2000...
So I would like to reverse engineer a allready excisting Method.
My problem is that I have a construction like this:
var acts = new Action[20];
for (int i = 0; i != 20; i++)
acts[i] = () => { Console.WriteLine(i); };
and by the way C# works all acts do the same (prints 20). But I want that that
acts[5]()
print 5
acts[11]()
prints 11 and so on.
So I need to compute 20 different delegates and I wonder what's a "nice" approach to do so. Of course I could just write:
acts[0] = () => Console.WriteLine(0);
acts[1] = () => Console.WriteLine(1);
acts[2] = () => Console.WriteLine(2);
acts[3] = () => Console.WriteLine(3);
....
But that's not a good approach in my eyey...
Anton's solution is nearly right, but he's copying the variable at the wrong time. You want this:
for (int i = 0; i != 20; i++)
{
int tmp = i;
acts[i] = () => Console.WriteLine(tmp);
}
This way the captured variable is tmp rather than i - and while there's only one i variable, whose value changes on each iteration, you get a "new" tmp variable for each iteration.
See Eric Lippert's blog posts on the topic (part 1, part 2) for more details.
(To answer the original question as per the title - you can't create an expression tree from a delegate in a useful way here - the only expression tree you can create is one which just calls the original delegate.)
Rewrite it like this:
for(int i = 0; i != 20; i++)
{
var x = i;
acts[i] = () => { Console.WriteLine(x); };
}

Categories

Resources