/// <summary> /// This is a helper method that returns the target object for a delegate. /// If the delegate was created to proxy a generic delegate, this will correctly /// return the original object, not the proxy. /// </summary> /// <param name="callback">The delegate to get the target for.</param> /// <returns>The object that is the callback target. This can return null if the callback represents a static object.</returns> /// <exception cref="ArgumentNullException">If callback is null.</exception> protected static object GetTarget(Delegate callback) { if (callback == null) { throw FxTrace.Exception.ArgumentNull("callback"); } ICallbackProxy proxy = callback.Target as ICallbackProxy; if (proxy != null) { return(proxy.OriginalTarget); } return(callback.Target); }
/// <summary> /// This is a helper method that performs a Delegate.Remove, but knows /// how to unwrap delegates that are proxies to generic callbacks. Use /// this in your Unsubscribe implementations. /// </summary> /// <param name="existing">The existing delegate to remove the callback from.</param> /// <param name="toRemove">The callback to remove.</param> /// <returns>A new value to assign to the existing delegate.</returns> protected static Delegate RemoveCallback(Delegate existing, Delegate toRemove) { if (existing == null) { return(null); } if (toRemove == null) { return(existing); } ICallbackProxy toRemoveProxy = toRemove.Target as ICallbackProxy; if (toRemoveProxy == null) { // The item to be removed is a normal delegate. Just call // Delegate.Remove return(Delegate.Remove(existing, toRemove)); } toRemove = toRemoveProxy.OriginalDelegate; Delegate[] invocationList = existing.GetInvocationList(); bool removedItems = false; for (int idx = 0; idx < invocationList.Length; idx++) { Delegate item = invocationList[idx]; ICallbackProxy itemProxy = item.Target as ICallbackProxy; if (itemProxy != null) { item = itemProxy.OriginalDelegate; } if (item.Equals(toRemove)) { invocationList[idx] = null; removedItems = true; } } if (removedItems) { // We must create a new delegate containing the // invocation list that is is left existing = null; foreach (Delegate d in invocationList) { if (d != null) { if (existing == null) { existing = d; } else { existing = Delegate.Combine(existing, d); } } } } return(existing); }