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.
Related
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();
could you explain me one example with delegate and lambda expression
List<Func<int>> list = new List<Func<int>>();
for (int i = 0; i < 10; i++)
{
list.Add(() => i);
}
foreach (var func in list)
{
Console.WriteLine(func());
}
I understand, that I have List of refers to methods whithout params and returns Int, but why it returns 10 times max value from loop? How it works? Thx!
It is closure when you do:
(() => i)
The lambda gets the original variable i, not a copy, so you get 10 ten times - because on calling delegate the original value of i is 10 (after loop)
If you change code and add local temp variable you will get 0 1 2 3 4 5 6 7 8 9:
for (int i = 0; i < 10; i++)
{
int j = i;
list.Add(() => j);
}
You can read about closures here:
Closures
When you pass variable inside of delegate's method it is its link, and not it's value that is used inside the delegate.
We create list of functions:
List<Func<int>> list = new List<Func<int>>();
Here we initialize list with functions and every function should use reference to memory where i variable is stored when it's fired :
for (int i = 0; i < 10; i++)
{
list.Add(() => i);
}
Now it is time to fire each function but at this time for loop is already finished executing and i variable holds its final value of 10. Remember that delegate can always find parameter because it holds reference to it. It could not be garbage collected :
foreach (var func in list)
{
// by the time we do it it has value of 10
Console.WriteLine(func());
}
The reason for that is that the lambda () => i captures the local variable i. This means that i will not be evaluated when it is added to the list but when you actually invoke the lambda with ().
At the time this happens in your code (Console.WriteLine(func());) the value of i is already 10 because the for loop has finished.
If you want to avoid this behaviour you have to copy the value of i into a local variable that will not change after the lambda has been created.
for (int i = 0; i < 10; i++)
{
int tmp = i;
list.Add(() => tmp);
}
Actually the lambda expression is a delegate, and you calling it after the loop ends and at that time i has value 10, so when the delegates are getting called, they all have i value 10 as same copy is used due to closure, you will need to write as #Roma suggested for it to work as you expect it to, otherwise it will,
this :
for (int i = 0; i < 10; i++)
{
list.Add(() => i);
}
can be looked as :
int i;
for (i=0; i < 10; i++)
{
list.Add(() => i);
}
int i = 0;
foreach (var logInAlarm in logInAlarms)
{
//Custom Code
//For comparison reason i need to access the next logInAlarm in the list.
var nextDate = logInAlarms[i + 1].Date;
i++;
}
I came up with an idea to add a counter variable and later access the element using that counter. Is this the best way?
You are better using the existing for loop which can stop an out of bounds error, but your approach is more or less correct
for(int i = 0; i < logInAlarms.Length - 1; i++)
var nextDate = logInAlarms[i+1].Date;
Test code for the end of array
var arr = Enumerable.Range(0, 5).ToArray();
for (int i = 0; i < arr.Length - 1; i++)
Console.Write(arr[i]);
Console.ReadLine();
Because you're dealing with a collection that has an indexer property accepting an integer (for instance an array or List<T>), you should use a for loop.
for (int v = 1; v < logInAlarms.Length; v++)
{
var current = logInAlarms[v - 1];
var next = logInAlarms[v];
// use current and next
}
However, if you weren't dealing with an array or List<T> and were instead using any sort of IEnumerable as the foreach loop supports, I would use this more generalized code.
var enumerator = logInAlarms.GetEnumerator();
if(enumerator.MoveNext())
{
var current = enumerator.Current;
while (enumerator.MoveNext())
{
var next = enumerator.Current;
// use current and next
current = next;
}
// current is now the last node, to which there is no "next." Deal with that or ignore it as you see so fit.
}
I suggest this, again, only because it will work any time that a foreach does, whereas a for loop will only work in certain instances (ElementAt notwithstanding). If you can use a for, do, but if you can't, this will work.
Just for fun, you could even write a helper function. You'd need to use Enumerable.Cast<T> if your original type implemented IEnumerable and not IEnumerable<T>, but this would still be pretty useful if you do a lot like this. I've also implemented a using block as suggested by #JeppeStigNielsen in a comment here, you may or may not want to do that in the first example, depending on whether your implementation implements IEnumerable<T> rather than IEnumerable (which is being phased out anyway, and is barely used).
public IEnumerable<Tuple<T, T>> GetPairs<T>(IEnumerable<T> coll)
{
using (var enumerator = logInAlarms.GetEnumerator())
{
if(enumerator.MoveNext())
{
var current = enumerator.Current;
while (enumerator.MoveNext())
{
var next = enumerator.Current;
yield return new Tuple<T, T>(current, next);
current = next;
}
}
}
}
I'm trying to use the Array.ForEach() extension method to loop through for a list of filtered elements from an array and then modify those values, unfortunately that doesn't seem to work I'm guessing because it doesn't actually modify the reference value of each element.
Is there any way to do this besides storing the results of the Array.ForEach() into a seperate array and then cloning that array to the original array? Also I know I could obviously do all of this without cloning if I use a for loop but if I could do it this way it would be cleaner and would be less code.
Here's the snippet:
Array.ForEach(Array.FindAll(starts, e => e < 0), e => e = 0);
ForEach simply isn't intended to do this - just like you wouldn't be able to do this with a foreach loop.
Personally I'd just use a for loop - it's easy to read and clear:
for (int i = 0; i < array.Length; i++)
{
// Alternatively, use Math.Max to pull up any negative values to 0
if (array[i] < 0)
{
array[i] = 0;
}
}
It really is simple - anyone will be able to understand it.
Now you could write your own extension method instead. You could write one to replace all values which satisfy a predicate with a fixed value, or you could write one to replace all values entirely... but I don't think it's really worth it. As an example of the latter:
public static void ReplaceElements<T>(this T[] array,
Func<T, T> replacementFunction)
{
// TODO: Argument validation
for (int i = 0; i < array.Length; i++)
{
array[i] = replacementFunction(array[i]);
}
}
Then call it with:
starts.ReplaceElements(x => Math.Max(x, 0));
I'd personally still use the for loop though.
(You could potentially change the above very slightly to make it take IList<T> and use Count instead. That would still work with arrays, but also List<T> etc too.)
You can do that with ref and delegates. However, I don't think it adds much value.
public delegate void RefAction<T>(ref T value);
public static void ForEachRef<T>(this T[] array, RefAction<T> action)
{
for (int i = 0; i < array.Length; ++i) action(ref array[i]);
}
You can use it as follows:
var myArray = new int[];
myArray.ForEachRef((ref int i) => i = whateverYouLike());
From the standpoint of possibility, there could be an interface IRefEnumerable<T> which iterates some container with assignable elements.
array = array.Select(x => (x < 0) ? 0: x).ToArray();
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); };
}