/// <summary>
 /// Invokes the method bound to target, with double dispatch
 /// </summary>
 public static TResult SurrogateInvoke <T, TResult>(this object target, Func <T, TResult> method, T arg, Func <TResult> orElse, TResult defaultResult)
 {
     target = target ?? throw new ArgumentNullException(nameof(target));
     method = method ?? throw new ArgumentNullException(nameof(method));
     if (!ReferenceEquals(target, method.Target) && !target.GetType().IsValueType)
     {
         throw new InvalidOperationException($"{nameof(method)} must be bound to {nameof(target)}");
     }
     return(DoubleDispatchObject.CreateSurrogate(method, default(T), orElse, defaultResult).Invoke(arg));
 }
 /// <summary>
 /// Invokes the method bound to target, with double dispatch
 /// </summary>
 public static void SurrogateInvoke <T>(this object target, Action <T> method, T arg, Action orElse)
 {
     target = target ?? throw new ArgumentNullException(nameof(target));
     method = method ?? throw new ArgumentNullException(nameof(method));
     if (!ReferenceEquals(target, method.Target) && !target.GetType().IsValueType)
     {
         throw new InvalidOperationException($"{nameof(method)} must be bound to {nameof(target)}");
     }
     DoubleDispatchObject.CreateSurrogate(method, default(T), orElse).Invoke(arg);
 }
 public static DoubleDispatchObject EnsureThreadSafe(this object target, ref DoubleDispatchObject dispatchObject) =>
 EnsureThreadSafe(target, ref dispatchObject, obj => new DoubleDispatchObject(obj));