Every once in a while when I write code that deals with Anonymous Delegates, I still kinda freak out when it comes to the behavior of closures and the variable scoping that goes along with it. For example, the following code uses a
List<T>.Find() Predicate to search for items in the list and requires that a dynamic value is compared to:
public void AddScript(ScriptItem script)
ScriptItem match = null;
// *** Grab just the path
script.FileId = Path.GetFileName(script.Src).ToLower();
match = this.InternalScripts.Find(
ScriptRenderModes mode = this.RenderMode; // demonstrate this pointer
return (item.FileId == script.FileId);
if (match == null)
match = script;
Predicate<T> signature requires a boolean return value and an input parameter of any type (the
<T>). The input parameter will be the item iterated over and is of the same time as the list. But the question then becomes: How do you compare that object against a dynamic value?
The freaky thing is the script variable in the AddScript function. It's passed in as a parameter to the outer function so it's effectively a local variable, but yet it is fully visible in the anonymous delegate's own private body. The delegate is in effect just another function, but what's different here is that the anonymous delegate inherits the variable scope of the containing method that is calling it.
To contrast if I were to call an explicit method to handle the Find filter:
match = this.InternalScripts.Find(Exists(script2));
and then create a method that matches this signature I can't access the script variable so this fails to compile:
bool Exists(ScriptItem script2)
return (script2.FileId == script.FileId); // FAILS obviously due to scoping
because script isn't available.
Behind the scenes the C# compiler creates a dynamic delegate class that includes fields for each of the local variables that need to be in scope, so when script is referenced in the delegate's body it's really referencing the equivalent of this.script. The compiler fixes up the code so that the script property is set when before the method call is made so the delegate code ‘appears’ to be referencing a variable. If the this pointer is referenced in the delegate code, the compiler also creates a field that holds a reference to the calling class and then fixes up any calls to this to this member instead.
Here's what the compiler generated class looks like:
private sealed class <>c__DisplayClass2
public wwScriptContainer <>4__this;
public ScriptItem script;
public bool <AddScript>b__0(ScriptItem item);
and the actual delegate method on the class:
public bool <AddScript>b__0(ScriptItem item)
ScriptRenderModes mode = this.<>4__this.RenderMode;
return (this.script.Src == item.Src);
Notice that the this pointer is actually referencing a property that has the parent class assigned to it. It's all compiler sugar as well as Visual Studio's Intellisense that gives you the impression that you are in fact inside of closure method. Incidentally one thing that DOESN'T work is checking the this. pointer in the debugger while you are in the delegate code. This cannot be accessed in the debugger inside of the delegate code which would presumably cause some confusion of whether this should point at the delegate (and reveal the compiler magic) or the calling container's class.
This concept of anonymous delegates and closure scoping is EXACTLY what makes Lambda Expressions work in C# 3.0. Lambdas are just glorified Anonymous Delegates. In fact, the Find() predicate above can also be expressed as a Lambda expression:
match = this.InternalScripts.Find( item => item.FileId == script.FileId );
Other Posts you might also like