Table of Contents

Memoizer Class

Definition

Namespace
Bodu.Functional
Assembly
Bodu.Core.dll
Package
Bodu.Core 1.0.1
Source
Memoizer.cs

Provides factory methods that wrap a function with a thread-safe cache, so each distinct argument is computed at most once and subsequent calls return the stored result.

public static class Memoizer
Inheritance
Memoizer
Inherited Members

Remarks

Results are cached in a ConcurrentDictionary<TKey, TValue>. Only successful results are stored: if the underlying function throws, nothing is cached and the next call retries. A null result is a valid cached value. For sequential use the function runs exactly once per distinct argument; under concurrent first access for the same argument the function may run more than once, but only one result is published.

Arguments are constrained to non-nullable types because they are used as dictionary keys. Memoizing a recursive function requires the function to call the memoized delegate for its recursive step.

The cache is unbounded and never evicts: every distinct argument's result is retained for the lifetime of the memoized delegate. Memoizing a function over an unbounded argument domain therefore grows memory without limit; for bounded caching with eviction, use EvictingDictionary<TKey, TValue> from the Bodu.Collections package instead.

Methods

Memoize<TArg, TResult>(Func<TArg, TResult>)

Wraps a single-argument function with a cache that uses the default equality comparer for its argument.

public static Func<TArg, TResult> Memoize<TArg, TResult>(Func<TArg, TResult> func) where TArg : notnull

Parameters

func Func<TArg, TResult>

The function to memoize.

Returns

Func<TArg, TResult>

A memoizing wrapper around func.

Type Parameters

TArg

The argument type.

TResult

The result type.

Examples

var square = Memoizer.Memoize<int, int>(n => ExpensiveSquare(n));

int a = square(8); // runs ExpensiveSquare
int b = square(8); // returns the cached result

Exceptions

ArgumentNullException

func is null.

Memoize<TArg, TResult>(Func<TArg, TResult>, IEqualityComparer<TArg>?)

Wraps a single-argument function with a cache that uses the specified equality comparer for its argument.

public static Func<TArg, TResult> Memoize<TArg, TResult>(Func<TArg, TResult> func, IEqualityComparer<TArg>? comparer) where TArg : notnull

Parameters

func Func<TArg, TResult>

The function to memoize.

comparer IEqualityComparer<TArg>

The comparer used to compare arguments, or null to use the default comparer.

Returns

Func<TArg, TResult>

A memoizing wrapper around func.

Type Parameters

TArg

The argument type.

TResult

The result type.

Examples

// Case-insensitive cache: "Hello" and "HELLO" resolve to one entry.
var lengthOf = Memoizer.Memoize<string, int>(s => s.Length, StringComparer.OrdinalIgnoreCase);

int x = lengthOf("Hello"); // computed
int y = lengthOf("HELLO"); // cache hit

Exceptions

ArgumentNullException

func is null.

Memoize<T1, T2, TResult>(Func<T1, T2, TResult>)

Wraps a two-argument function with a cache keyed on the pair of arguments.

public static Func<T1, T2, TResult> Memoize<T1, T2, TResult>(Func<T1, T2, TResult> func) where T1 : notnull where T2 : notnull

Parameters

func Func<T1, T2, TResult>

The function to memoize.

Returns

Func<T1, T2, TResult>

A memoizing wrapper around func.

Type Parameters

T1

The first argument type.

T2

The second argument type.

TResult

The result type.

Examples

// Cache keyed on the (x, y) argument pair.
var add = Memoizer.Memoize<int, int, int>((x, y) => SlowAdd(x, y));

int s1 = add(3, 4); // computed
int s2 = add(3, 4); // cache hit

Exceptions

ArgumentNullException

func is null.

Applies to

ProductVersions
.NET8, 10