Ensure that ICommand implementation properly uses weak references I am building an implementation of System.Windows.Input.ICommand that is like the commonly used RelayCommand, but doesn't keep a strong reference to targets of the delegates it uses. Such a structure is useful for when a control wants to expose some of its functionality as a command (which can be assigned to a ViewModel). Using a traditional RelayCommand would cause a memory leak, because the RelayCommand would contain strong references to the delegates that it runs, which in turn contain strong references to the control. Here is the code:

public class WeakRelayCommand : ICommand
{
    public WeakRelayCommand(Action&lt;object&gt; executeCallback, Func&lt;object, bool&gt; canExecuteCallback = null)
    {
        ExecuteTargetReference = new WeakReference&lt;object&gt;(executeCallback.Target);
        if (canExecuteCallback != null)
            CanExecuteTargetReference = new WeakReference&lt;object&gt;(canExecuteCallback.Target);
        ExecuteCallbackInfo = executeCallback.GetMethodInfo();
        CanExecuteCallbackInfo = canExecuteCallback?.GetMethodInfo();
    }

    private WeakReference&lt;object&gt; ExecuteTargetReference;
    private WeakReference&lt;object&gt; CanExecuteTargetReference;
    private MethodInfo ExecuteCallbackInfo;
    private MethodInfo CanExecuteCallbackInfo;

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        if (CanExecuteCallbackInfo == null)
            return true;
        object canExecuteTarget = null;
        if (CanExecuteTargetReference?.TryGetTarget(out canExecuteTarget) ?? false)
        {
            return (bool)CanExecuteCallbackInfo.Invoke(canExecuteTarget, new[] { parameter });
        }
        else
            return false; //Target of the delegate for CanExecute has been garbage collected
    }

    public void Execute(object parameter)
    {
        object executeTarget = null;
        if (ExecuteTargetReference?.TryGetTarget(out executeTarget) ?? false)
        {
            ExecuteCallbackInfo.Invoke(executeTarget, new[] { parameter });
        }
        //Cannot execute the command if the target of the Execute delegate has been garbage collected
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}


The basic summary is that instead of holding strong references to delegates, which in turn hold strong references to the delegates' targets of invocation, it instead holds a reference to the MethodInfo associated with the actual method of the delegate, and holds a WeakReference to the targets of invocation separately from the method. This way, the targets of invocation are free to be garbage collected by the garbage collector.

I have tested this implementation and it works just fine as an implementation of ICommand, and it appears to properly use WeakReferences to achieve my objective. Can I get a verification that this is in fact the case?
The implementation works fine if the passed delegate is an instance method, because that prevents the method from being garbage collected.

But that is not necessarily the case. Lambda expression, for instance, will be garbage collected sometime because they are not referenced somewhere else. 
That may result in strange not reproducible bugs that are hard to debug.

The following code (with a simplified version of the WeakRelayCommand class) shows that the weak reference approach does not work for static methods and lambda expressions with closures.

void Main()
{
    var longLiveObject = new DummyObject();
    var commands = GetActions(longLiveObject);

    GC.Collect();
    GC.WaitForPendingFinalizers();

    foreach (var command in commands)
        Console.WriteLine(command.Name + "\t IsAlive:" + command.IsAlive);
}

private static WeakAction[] GetActions(DummyObject longLiveObject)
{
    var localObj = new DummyObject();
    return new []
    {
        new WeakAction("InstanceMethod (short living)", localObj.InstanceMethod),
        new WeakAction("InstanceMethod (long living)", longLiveObject.InstanceMethod),
        new WeakAction("StaticMethod", DummyObject.StaticMethod),
        new WeakAction("LamdaExpression (without closure)", o =&gt; { }),
        new WeakAction("LamdaExpression (with closure)", o =&gt; localObj.InstanceMethod(o)),
    };
}

// Define other methods and classes here
public class DummyObject
{
    public void InstanceMethod(object obj) { }
    public static void StaticMethod(object obj) {}  
}

public class WeakAction
{
    private readonly WeakReference&lt;object&gt; _targetReference;
    private readonly MethodInfo _callbackInfo;

    public WeakAction(string name, Action&lt;object&gt; executeCallback)
    {
        Name = name;
        _targetReference = new WeakReference&lt;object&gt;(executeCallback.Target);
        _callbackInfo = executeCallback.GetMethodInfo();        
    }

    public string Name { get; }
    public bool IsAlive
    {
        get
        {
            object obj;
            return _targetReference.TryGetTarget(out obj);
        }
    }
}


Output:

InstanceMethod (short living)        IsAlive:False
InstanceMethod (long living)         IsAlive:True 
StaticMethod                        IsAlive:False 
LamdaExpression (without closure)   IsAlive:True 
LamdaExpression (with closure)      IsAlive:False