This works because IsAmType is not a lambda, but rather it is a local function. And that works because local functions are "just" syntax sugar and are "expanded" (in C# it's called "lowering") to a (compiler generated) "regular" method on your class. So, something like this
public class Program
{
private static int Foo(int[] toSum)
{
var sum = 0;
foreach (var element in toSum.Where(ShouldSelect))
sum += element;
return sum;
bool ShouldSelect(int num) => num % 2 == 0;
}
}
Gets lowered to something like this (ignoring that foreach is also syntax sugar that gets lowered) which then gets successfully compiled.
public class Program
{
private static int Foo(int[] toSum)
{
var sum = 0;
foreach (var element in toSum.Where(SomeCompileGeneratedNameForShouldSelect))
sum += element;
return sum;
}
internal static bool SomeCompileGeneratedNameForShouldSelect(int num)
{
return num % 2 == 0;
}
}
If IsAmType actually were a lambda (an anonymous function), you'd (expectedly) get a compiler error, i.e. this
public class Program
{
private static int Foo(int[] toSum)
{
var sum = 0;
foreach (var element in toSum.Where(bar))
sum += element;
return sum;
Predicate<int> bar = num => num % 2 == 0;
}
}
Doesn't compile with the error message:
error CS0841: Cannot use local variable 'bar' before it is declared
You can see what these examples (roughly) get lowered to here
It is very common for local functions to be defined at the end of the scope, and if local functions capture a variable (local functions can capture variables much like anonymous functions capture variables) from the surrounding context they actually have to be defined after those variables it captures are defined.
Whether or not this (and local functions) are good practice entirely depends on the context and is largely opinion based, as such I won't go into detail on that.
bool IsAmTypeisn't a lambda, it's a local function