LINQ Walk[source]

xml
<glacius:metadata>
    <title>LINQ Walk</title>
    <description>Implementation of a walk() extension method for LINQ</description>
    <category>Legacy blog posts</category>
    <category>Programming</category>
    <category>C#</category>
</glacius:metadata>
<glacius:macro name="legacy blargh banner">
    <properties>
        <originalUrl>https://tmont.com/blargh/2010/3/linq-walk</originalUrl>
        <originalDate>2010-03-24T08:05:57.000Z</originalDate>
    </properties>
</glacius:macro>
<p>
  So, we all know that
  <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/">LINQ</a>
  is rad. Not in that silly faux-SQL syntax, but in the declarative, fluent syntax.
</p>
<p>
  But the sad part is that there is no <code>walk</code> extension method. Walk is a 
  functional programming staple that iterates over a collection of stuff and applies a 
  callback to each item.
</p>
<p>
  You might be thinking, "but there is a <code>ForEach()</code> extension method on 
  <code>List</code>!". And you would be wrong, because there is a subtle, yet important 
  difference between <code>IEnumerable</code> and <code>IList</code>.
</p>
<p>
  <code>IEnumerable</code> is late-binding. That means you can do whatever you want to 
  it, but execution is deferred until you actually enumerate the enumeration, i.e. using a 
  <code>foreach</code> construct. In a list, there is no deferred execution. This deferred 
  execution is accomplished through the magic of closures and expression trees.
</p>
<p>In the meantime, here is a fluent implementation of <code>walk</code>:</p>
<glacius:code lang="csharp"><![CDATA[public static class LinqExtensions {
	public static IEnumerable<T> Walk<T>(this IEnumerable<T> source, Action<T> action) {
		foreach (var t in source) {
			action(t);
			yield return t;
		}
	}
}]]></glacius:code>
<p>You can prove that this is in fact using deferred execution with a simple test:</p>
<glacius:code lang="csharp"><![CDATA[class Program {
	class Foo {
		public int Bar { get; set; }
		public override string ToString() {
			return string.Format("Foo(Bar={0})", Bar);
		}
	}
	static void Main() {
		IEnumerable<Foo> foos = new[] { new Foo { Bar = 2 }, new Foo { Bar = 1 }, new Foo { Bar = 3 } };
		Console.WriteLine("IEnumerable.Walk():");
		foos.Walk(Console.WriteLine);
		Console.WriteLine();
		Console.WriteLine("List.ForEach():");
		foos.ToList().ForEach(Console.WriteLine);
		Console.WriteLine();
		Console.ReadLine();
	}
}]]></glacius:code>
<p>The output looks like this:</p>
<p class="text-center">
  <img glacius:src="linqwalk1.png" alt="LINQ walk output" />
</p>
<p>
  Notice that nothing got printed the first time through, using the <code>Walk()</code> extension 
  method. There's your deferred execution. That means our extension method did not enumerate the 
  enumeration, so it's safe and efficient to use walk in a normal linq expression where you are 
  depending on deferred execution, like this:
</p>
<glacius:code lang="csharp"><![CDATA[
IEnumerable<Foo> foos = new[] { new Foo { Bar = 2 }, new Foo { Bar = 1 }, new Foo { Bar = 3 } };
Console.WriteLine("Doing more stuff:");
var listOStuff = foos
	.Where(foo => foo.Bar >= 2)
	.Walk(foo => foo.Bar += 10)
	.Select(foo => new Baz { Foofy = foo })
	.Walk(baz => baz.Foofy.Bar--)
	.OrderBy(baz =>; baz.Foofy.Bar);
foreach (var stuff in listOStuff) {
	Console.WriteLine(stuff);
}
Console.ReadLine();]]></glacius:code>
<p class="text-center">
  <img glacius:src="linqwalk2.png" alt="LINQ walk output 2" />
</p>
<p>Well, maybe that's not "normal." Whatever.</p>