Skip to content

C# Static Local Function — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about C# Static Local Function. We cover key concepts, practical examples, and best practices.

Your local function does not capture any variables from the enclosing scope, but the compiler still generates a closure class, allocating garbage every call. The static keyword on a local function guarantees no capture and eliminates the allocation.

Wrong

public IEnumerable<int> ProcessData(int[] items)
{
    return items.Where(IsValid);

    bool IsValid(int x) => x > 0; // No capture — but compiler may still allocate
}

Output: Works, but the compiler creates a closure instance each time ProcessData is called, even though IsValid does not capture any variables.

public IEnumerable<int> ProcessData(int[] items)
{
    return items.Where(IsValid);

    static bool IsValid(int x) => x > 0; // Guaranteed no allocation
}

Output: Same result, zero allocation. The static keyword forces the compiler to verify the function does not reference this or any local variables.

If you try to capture with a static local function:

public IEnumerable<int> ProcessData(int[] items, int min)
{
    return items.Where(IsValid);

    static bool IsValid(int x) => x > min; // CS8820: Cannot reference local variable
}

Output: Compiler error CS8820 telling you to remove static or pass min as a parameter.

Prevention

  • Mark local functions static when they do not capture enclosing variables.
  • Pass captured values as parameters instead of closing over them.
  • Use static local functions inside hot paths (loops, LINQ callbacks, tight iterations).
  • Combine with lambda conversion — the static local function can be converted to a delegate without allocation in some cases.
  • Profile before optimizing — one allocation per call is usually fine; avoid it in high-throughput code.

Common Mistakes with static local function

  1. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  2. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  3. Using head and tail instead of pattern matching, causing runtime errors on empty lists

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

Do static local functions always avoid allocation?

When converted to a delegate, static local functions may still allocate the delegate itself. However, the closure object is eliminated. The delegate is cached by the compiler if the function is static and does not capture anything.

What happens if I remove static and the function does not capture?

The compiler may still optimize it. In .NET 6+, the JIT can elide the closure allocation for non-static local functions that do not capture. Using static makes the intent explicit and guarantees the optimization.

Can I use static local functions in async methods?

Yes. A static local function inside an async method works the same way — it cannot capture variables from the async method's scope. Pass any needed values as parameters.

Static local functions are used in high-performance paths in Durga Antivirus Pro's pattern matching engine. For more C#, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro