Abstract. This is tutorial text on “function closures” in C#. Some theory is explained, and several C# examples are shown.
Introduction
Function closures” are tricky and sometimes difficult to understand. They are possible and present in C# language. Every ambitious C# developer should be familiar with function closures, either to use them or to competently read/debug other people's code. They offer fancy encapsulation in the form of a “captured variable” that is not so easy to comprehend. This tutorial tries to explain it and provide a sufficient number of examples. The intended audience is Intermediate C# developer and above.
While many might disagree, from the readability of the code point of view, I would argue that it is more readable to see classical encapsulation via a class than a “function closure” in the code. But of course, opinions differ, and many like to use the fancy staff.
Theoretical background
Before some practical examples, some theoretical background is needed. In this article, we will not go for the full rigor in definitions, like one that can be found in a very good article [1]. We are more focused on explaining and comprehending the basic concepts, leaving a more formal approach to further reading of materials like references enclosed.
Simplified definitions
Here are some plain language explanations.
How to create closures in C#?
Closures are created when you are inside a function/method in the C# reference variable from the “above scope,” and then you pass that function as a delegate around. That variable from the “above scope” is passed around with that function delegate.
How is the closure implemented?
When the compiler notices that you are inside a function accessing the variable from the above scope, it creates a record in which it stores 1) the function in question, 2) the variable from the “above scope& (popularly called captured variable) and passes them around together.
Analogy model for thinking about implementation
One very good way to think about it and represent it in your mind is that the compiler creates a private class in which he encapsulates that variable from the “above scope” (so-called “captured variable”) and transforms a “function closure” into a method of that class and passes that private class around.
More formal definitions
Here are more formal definitions, still not as formal as [1]. You can skip this in the first reading.
A programming language with first-class functions.
A programming language is said to have “First-class functions” if it treats functions as first-class citizens, meaning that functions can be assigned to variables, passed as arguments to another function, etc. C# is definitely such a language since delegates can be assigned to variables and passed around. Basically, it says that if you can somehow obtain a “pointer to a function” ( in C/C++ terminology) and pass it around, that is a special feature of that language, which we call “first-class function language”. In such languages, typically, “function closure” concepts have sense and are possible. So, the concept of “function closure” has no sense in every programming language, just in some languages, and C# is one of them.
Free variable in C#
That is a variable that is used locally but defined in the enclosing scope. That is what we sometimes call “variable from the above scope”.
Lexical scope in C#
That is the definition area of an expression. For the variable, that is an area in which the variable is defined/created. It is often called “static scope ” since it can be deduced from static program text.
What are closures in C#
The “function closure” is the concept of implementing lexically scoped variable binding in a language with first-class functions. Practically, that means that “function closure” is storing a record (structure) of a function together with references/values of any free variables it has.
When closures are implemented?
Closures are typically implemented as a special data structure that contains 1) a pointer to the function code; and 2) a representation of any “free variable” at the time of closure creation. The second part is sometimes referred to as the “function lexical environment”.
Example 1. created, using local function syntax.
using System;
public delegate void MyAction();
public class TestClass
{
public static MyAction CreateClosureFunction()
{
// We created a scope for this variable
int i_capturedVariable = 0;
// Using local function syntax
void ff()
{
// This is a variable from the "above scope"
// and it will be captured
++i_capturedVariable;
Console.WriteLine("i_capturedVariable: " + i_capturedVariable);
}
return ff;
}
}
class Program
{
static void Main(string[] args)
{
MyAction? ClosureFunction1 = TestClass.CreateClosureFunction();
// Here the scope is closed, and the variable
// i_capturedVariable no longer exists
Console.WriteLine("ClosureFunction1 invocation:");
ClosureFunction1();
ClosureFunction1();
ClosureFunction1();
}
}
The above code is an example of a “function closure” in C#.
It is defined in “above scope” to the function scope where it is used. In the above terminology, that is a “free variable,” and it will be bound to the function during assignment to the delegate ClosureFunction1. In the above terminology, it will become a “captured variable”. That variable is not in the function scope but is used inside the function, so when the function is passed around, it needs to be encapsulated with the function. The existence of such a variable is the main and only reason why “function closure” needs to be created. The main trick here is that at the moment in which the function is invoked/executed, the scope in which the variable i_capturedVariable is defined will no longer exist, so to make the function work, the compiler needs to encapsulate that variable with the function itself.
What is delegate ClosureFunction1?
Function closures in C# are created only when the function is passed around via a delegate, which is analogous to the C/C++ “pointer to a function”.
What is an assignment to the delegate ClosureFunction1?
It looks like an ordinary assignment to the delegate; nothing in the code visibly indicates that the “function closure” is being created and assigned. All work is done by the compiler in the background. That is why is sometimes not easy to recognize that “function closure” is being created. Only by decompiling the C# code one can see that the variable i_capturedVariable is being encapsulated and passed together with the function.
What is the execution result?
What we see is not only that “function closure” has access to the variable i_capturedVariable from the above scope, although that scope no longer exists, but also that it can use that variable to remember the state between invocations. That is why we say that the variable i_capturedVariable from the “above scope” is a “captured variable”.
Result of invocation/execution of closure function
The fact that now “function closure,” represented by delegate ClosureFunction1, carries its own state encapsulated within itself is a feature that is often a motivation for the creation and usage of “function closures”. That is a fancy way to encapsulate state with the function and is liked by many programmers.
Anonymous function syntax
Here is a practical example of C# “function closure” created using anonymous function syntax.
using System;
public delegate void MyAction();
class Program
{
static void Main(string[] args)
{
MyAction? ClosureFunction1 = null;
{
// We created a scope for this variable
int i_capturedVariable = 0;
// Using anonymous function syntax
ClosureFunction1 = delegate
{
// This is a variable from the "above scope"
// and it will be captured
++i_capturedVariable;
Console.WriteLine("i_capturedVariable: " + i_capturedVariable);
};
}
// Here the scope is closed, and the variable
// i_capturedVariable no longer exists
Console.WriteLine("ClosureFunction1 invocation:");
ClosureFunction1();
ClosureFunction1();
ClosureFunction1();
}
}



Join the conversation! Your thoughts help the community grow.