/// <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);
        }