ReSharper 2024.3 Help

Code inspection: Lambda expression/anonymous method must not have captures of the containing context

Lambda expressions in C# are usually associated with some performance and memory impact. Although the abstraction that lambda expressions provide is worth additional costs in most scenarios, these costs may not be acceptable for some hot path code.

To distinguish such code, you can use the [RequireStaticDelegate] attribute from JetBrains.Annotations. This attribute enforces allocation-less coding practices by reporting captures of the containing context in lambda expressions passed to parameters annotated with this attribute. Lambda expressions without any captures of the containing context only allocate the delegate instance once and cache it for the rest of the program execution, so such lambda expressions become allocation-less.

Here is an example of an API that expects users to compute the cached value using the Func delegate type input parameter.

class Cache { private Dictionary<string, int> _cache = new(); public int GetData(string key, [RequireStaticDelegate] Func<string, int> calculator) { if (!_cache.TryGetValue(key, out var value)) { value = _cache[key] = calculator(key); } return value; } }

... but it's too easy to make a mistake and capture the variable key instead of x parameter:

class CacheTest { public CacheTest() { var cache = new Cache(); var key = "abc"; // Warning: anonymous function // should not have captures of the containing context var a = cache.GetData(key, calculator: x => key.Length); } }

ReSharper will report such captures, but it will not suggest any quick-fixes — you need to make sure that your code works properly without capturing anything from the invocation context.

If you pass a method as the delegate parameter, ReSharper will suggest adding static modifier to the lambda expression when possible to prevent captures at the compiler level:

// Allocates on each call var a = cache.GetData(key, calculator: Compute); // Doesn't allocate var b = cache.GetData(key, calculator: static x => Compute(x));
Last modified: 11 February 2024