Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An anonymous method in C# is an unnamed, inline block of code explicitly defined using the delegate keyword that can be assigned directly to a delegate type. Introduced in C# 2.0, it provides a mechanism to instantiate delegates without requiring a separate, named method declaration in the containing class.

Syntax

The fundamental syntax requires the delegate keyword, an optional parameter list, and a statement block. It can also include optional static and async modifiers:
[static] [async] delegate [(input_parameters)] 
{ 
    // statement_block 
}

Delegate Binding and Instantiation

An anonymous method cannot exist independently; it must be coerced into a specific delegate type. The compiler verifies that the signature of the anonymous method matches the signature of the target delegate.
// Target delegate type
public delegate void ProcessData(int value);

// Instantiating the delegate using an anonymous method
ProcessData processor = delegate(int x) 
{
    Console.WriteLine(x * 2);
};

Parameter Omission

A distinct syntactic feature of anonymous methods—which differentiates them from C# 3.0 lambda expressions—is the ability to completely omit the parameter list if the parameters are not utilized within the statement block. When the parameter list is omitted, the anonymous method can be implicitly converted to a delegate type with any list of parameters, provided the delegate signature does not contain out parameters.
// The target delegate requires two parameters: (object, EventArgs)
EventHandler handler = delegate 
{ 
    // The parameter list is omitted entirely.
    // This is valid as long as the parameters are not needed in this block.
    Console.WriteLine("Invoked without explicitly declaring parameters."); 
};

Variable Capture (Closures)

Anonymous methods can access and modify local variables and parameters defined in their enclosing scope. This mechanism is known as a closure. When an outer variable is captured by an anonymous method, the compiler hoists the variable into a hidden compiler-generated class. The lifetime of the captured variable is extended to match the lifetime of the delegate instance, meaning the variable is not garbage collected until the delegate itself is eligible for collection.
int multiplier = 5; // Outer variable

Func<int, int> multiply = delegate(int input)
{
    // Captures the 'multiplier' variable from the outer scope
    return input * multiplier; 
};

multiplier = 10; 

// Invocation evaluates the captured variable at the time of execution, not definition.
// Result is 20, not 10.
int result = multiply(2); 

Static Anonymous Methods

Introduced in C# 9, the static modifier can be applied to an anonymous method to explicitly prevent the capture of local variables and instance state from the enclosing scope. This enforces strict isolation and avoids the hidden memory allocations associated with compiler-generated closure classes.
int outerVariable = 10;

// Valid: Does not capture outer variables
Func<int, int> square = static delegate(int x) 
{
    return x * x; 
};

// Invalid: Compilation error if attempting to capture 'outerVariable'
// Func<int, int> add = static delegate(int x) { return x + outerVariable; };

Asynchronous Anonymous Methods

Anonymous methods can be marked with the async modifier to enable asynchronous programming using the await keyword within the statement block. The target delegate must have a return type of void, Task, Task<T>, or another awaitable type.
Func<Task> asyncOperation = async delegate 
{
    await Task.Delay(1000);
    Console.WriteLine("Asynchronous operation completed.");
};

Type Inference and Natural Types

Historically, anonymous methods were strictly target-typed. However, starting with C# 10, anonymous methods possess a natural type and their return types can be inferred by the compiler, provided they have an explicitly typed parameter list. This allows them to be assigned to implicitly typed variables using the var keyword.
// C# 10 and later: The compiler automatically infers the natural type Func<int, string>
var intToString = delegate(int number) 
{ 
    return number.ToString(); 
};
If the parameter list is omitted, or if the return type cannot be unambiguously inferred from the return statements, the anonymous method does not have a natural type and remains strictly target-typed. In these scenarios, the compiler utilizes the return type of the target delegate to verify that all expressions within the return statements are implicitly convertible to that specific type.
// Target-typed: Parameter list is omitted, so 'var' cannot be used.
// The compiler enforces the target type (string) dictated by Func<string>.
Func<string> getGreeting = delegate
{
    return "Hello"; 
};

Limitations

  • out parameters: An anonymous method cannot omit its parameter list if the target delegate signature includes out parameters. This restriction exists because out parameters must be definitely assigned before returning, which is impossible if they are omitted and unnamed. (Omission is permitted for delegates with ref parameters).
  • Outer by-reference parameters: An anonymous method cannot capture or access in, ref, or out parameters defined in an enclosing outer scope.
  • ref struct capture: An anonymous method cannot capture ref struct types (such as Span<T> or ReadOnlySpan<T>) from the enclosing scope. This is a fundamental limitation of closures, as ref struct instances are strictly stack-allocated and cannot be hoisted into the heap-allocated compiler-generated closure class.
  • Jump statements: Control flow statements such as goto, break, or continue cannot be used to jump into or out of the anonymous method block.
Master C# with Deep Grasping Methodology!Learn More