/// <summary>
        ///     Test whether two collections are equivalent
        /// </summary>
        /// <param name="actual"></param>
        /// <returns></returns>
        protected override bool doMatch(IEnumerable actual)
        {
            // This is just an optimization
            if (expected is ICollection && actual is ICollection)
            {
                if (((ICollection)actual).Count != ((ICollection)expected).Count)
                {
                    return(false);
                }
            }

            CollectionTally tally = Tally(expected);

            return(tally.TryRemove(actual) && tally.Count == 0);
        }
        private bool DictionariesEqual(IDictionary expected, IDictionary actual, ref Tolerance tolerance)
        {
            if (expected.Count != actual.Count)
            {
                return(false);
            }

            var tally = new CollectionTally(this, expected.Keys);

            if (!tally.TryRemove(actual.Keys) || tally.Count > 0)
            {
                return(false);
            }

            foreach (var key in expected.Keys)
            {
                if (!ObjectsEqual(expected[key], actual[key], ref tolerance))
                {
                    return(false);
                }
            }

            return(true);
        }