Beispiel #1
0
        ///<summary>Registers callbacks to each soul, ensuring everything is cleaned up properly upon completion.</summary>
        public static RegistrationRemover InterdependentRegister(this ISoul soul1, Func<bool> tryComplete1, ISoul soul2, Func<bool> tryComplete2) {
            if (soul1 == null) throw new ArgumentNullException("soul1");
            if (tryComplete1 == null) throw new ArgumentNullException("tryComplete1");
            if (soul2 == null) throw new ArgumentNullException("soul2");
            if (tryComplete2 == null) throw new ArgumentNullException("tryComplete2");

            // forward declare the second registration canceller, so it can be referenced by the first registration
            RegistrationRemover cancelRegistration2 = null;
            var callCount = 0;
            Action skipOnceCancelRegistration2 = () => {
                if (Interlocked.Increment(ref callCount) == 2 && cancelRegistration2 != null)
                    cancelRegistration2();
            };

            // register the callbacks, linking their cancellation to each other
            var cancelRegistration1 = soul1.Register(() => { if (tryComplete1()) skipOnceCancelRegistration2(); });
            cancelRegistration2 = soul2.Register(() => { if (tryComplete2()) cancelRegistration1(); });
            
            // now that cancelRegistration2 has been initialized, we can allow it to be run
            skipOnceCancelRegistration2();

            // outside can force cleanup
            return () => {
                cancelRegistration1();
                cancelRegistration2();
            };
        }
Beispiel #2
0
        ///<summary>Registers callbacks to each soul, ensuring everything is cleaned up properly upon completion.</summary>
        public static RegistrationRemover InterdependentRegister(this ISoul soul1, Func <bool> tryComplete1, ISoul soul2, Func <bool> tryComplete2)
        {
            if (soul1 == null)
            {
                throw new ArgumentNullException("soul1");
            }
            if (tryComplete1 == null)
            {
                throw new ArgumentNullException("tryComplete1");
            }
            if (soul2 == null)
            {
                throw new ArgumentNullException("soul2");
            }
            if (tryComplete2 == null)
            {
                throw new ArgumentNullException("tryComplete2");
            }

            // forward declare the second registration canceller, so it can be referenced by the first registration
            RegistrationRemover cancelRegistration2 = null;
            var    callCount = 0;
            Action skipOnceCancelRegistration2 = () => {
                if (Interlocked.Increment(ref callCount) == 2 && cancelRegistration2 != null)
                {
                    cancelRegistration2();
                }
            };

            // register the callbacks, linking their cancellation to each other
            var cancelRegistration1 = soul1.Register(() => { if (tryComplete1())
                                                             {
                                                                 skipOnceCancelRegistration2();
                                                             }
                                                     });

            cancelRegistration2 = soul2.Register(() => { if (tryComplete2())
                                                         {
                                                             cancelRegistration1();
                                                         }
                                                 });

            // now that cancelRegistration2 has been initialized, we can allow it to be run
            skipOnceCancelRegistration2();

            // outside can force cleanup
            return(() => {
                cancelRegistration1();
                cancelRegistration2();
            });
        }
Beispiel #3
0
        ///<summary>Registers a callback to the dependent soul that only occurs if the necessary soul doesn't die first, ensuring everything is cleaned up properly.</summary>
        public static RegistrationRemover DependentRegister(this ISoul soul, Action action, ISoul necessarySoul)
        {
            if (soul == null)
            {
                throw new ArgumentNullException("soul");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            if (necessarySoul == null)
            {
                throw new ArgumentNullException("necessarySoul");
            }

            // when the necessary soul is the same soul as the dependent soul, assume the callback invocation will beat the registration removal
            if (ReferenceEquals(soul, necessarySoul))
            {
                necessarySoul = ImmortalSoul.Instance;
            }

            // avoid wrapping when possible
            if (necessarySoul.Phase == Phase.Dead)
            {
                return(EmptyRemover);
            }
            if (soul.Phase != Phase.Mortal)
            {
                action();
                return(EmptyRemover);
            }
            if (necessarySoul.Phase == Phase.Immortal)
            {
                return(soul.Register(action));
            }

            return(soul.InterdependentRegister(
                       () => {
                action();
                return true;
            },
                       necessarySoul,
                       () => necessarySoul.Phase == Phase.Dead));
        }
Beispiel #4
0
 public RegistrationRemover Register(Action action)
 {
     return(_subSoul.Register(action));
 }
Beispiel #5
0
 public RegistrationRemover Register(Action action) => _subSoul.Register(action);