Table of Contents

Weak references

In UI applications and event-driven systems, storing delegate callbacks can accidentally keep objects alive long after they should have been garbage collected. A view model that registers a callback with a long-lived service stays in memory as long as that service holds a reference to the callback, even if the view model's view has been navigated away from.

WeakReferenceCallback wraps a delegate in a WeakReference, allowing the garbage collector to reclaim the target object while the callback registration still exists.

How it works

using MADE.Runtime;

// Store a callback without preventing garbage collection of the target
var callback = new WeakReferenceCallback(myAction, typeof(MyResponse));

When the callback is invoked:

  • If the target object is still alive, the delegate executes normally.
  • If the target object has been garbage collected, the invocation is silently skipped.

Practical example: network request callbacks

The NetworkRequestManager in MADE.Networking uses WeakReferenceCallback internally to store success and error callbacks:

public void AddOrUpdate<TRequest, TResponse, TErrorResponse>(
    TRequest request,
    Action<TResponse> successCallback,
    Action<TErrorResponse> errorCallback)
    where TRequest : NetworkRequest
{
    var weakSuccess = new WeakReferenceCallback(successCallback, typeof(TResponse));
    var weakError = new WeakReferenceCallback(errorCallback, typeof(TErrorResponse));

    // Store weak references instead of strong references to the callbacks
    var requestCallback = new NetworkRequestCallback(request, weakSuccess, weakError);
    CurrentQueue.AddOrUpdate(request.Identifier.ToString(), requestCallback, (s, c) => requestCallback);
}

If the view model that registered the callback is disposed before the network request completes, the callback reference doesn't prevent garbage collection. The request still completes, but the callback is skipped.

Reflection helpers

The MADE.Runtime.Extensions.ReflectionExtensions class provides GetPropertyNames for retrieving the public property names of an object:

using MADE.Runtime.Extensions;

var user = new User { FirstName = "James", LastName = "Croft" };
IEnumerable<string> names = user.GetPropertyNames();
// ["FirstName", "LastName"]

When to use WeakReferenceCallback

  • Use it when storing callbacks in long-lived objects (managers, registries, caches) where the callback source may be short-lived.
  • Don't use it for callbacks that must always execute (e.g., critical cleanup logic). If the target is collected, the callback won't run.