public CleanableWeakComHandleTable(int?cleanUpThreshold = null, TimeSpan?cleanUpTimeSlice = null)
        {
            _table      = new Dictionary <TKey, WeakComHandle <TValue, TValue> >();
            _deadKeySet = new HashSet <TKey>();

            CleanUpThreshold = cleanUpThreshold ?? DefaultCleanUpThreshold;
            CleanUpTimeSlice = cleanUpTimeSlice ?? s_defaultCleanUpTimeSlice;
            _cleanUpState    = CleanUpState.Initial;
        }
        /// <summary>
        /// Cleans up references to dead objects in the table. This operation will return if it takes
        /// longer than <see cref="CleanUpTimeSlice"/>. Calling <see cref="CleanUpDeadObjects"/> further
        /// times will continue the process.
        /// </summary>
        public void CleanUpDeadObjects()
        {
            this.AssertIsForeground();

            if (!_needsCleanUp)
            {
                return;
            }

            var timeSlice = new TimeSlice(CleanUpTimeSlice);

            if (_cleanUpState == CleanUpState.Initial)
            {
                _cleanUpEnumerator = _table.GetEnumerator();
                _cleanUpState      = CleanUpState.CollectingDeadKeys;
            }

            if (_cleanUpState == CleanUpState.CollectingDeadKeys)
            {
                if (_cleanUpEnumerator == null)
                {
                    // The enumerator got reset while we were collecting dead keys.
                    // Go ahead and remove the dead keys that were already collected before
                    // collecting more.
                    if (!RemoveDeadKeys(timeSlice))
                    {
                        return;
                    }

                    _cleanUpEnumerator = _table.GetEnumerator();
                }

                if (!CollectDeadKeys(timeSlice))
                {
                    return;
                }

                InvalidateEnumerator();
                _cleanUpState = CleanUpState.RemovingDeadKeys;
            }

            if (_cleanUpState == CleanUpState.RemovingDeadKeys)
            {
                if (!RemoveDeadKeys(timeSlice))
                {
                    return;
                }

                _cleanUpState = CleanUpState.Initial;
            }

            _needsCleanUp = false;
        }