コード例 #1
0
        public static bool AreArraysEqual <TElement>(
            TElement[] array1,
            TElement[] array2,
            EqualityComparison <TElement> comparison)
        {
            if (comparison == null)
            {
                throw new ArgumentNullException("comparison");
            }

            if (array1 == array2)
            {
                return(true);
            }

            if ((array1 == null) || (array2 == null) || (array1.Length != array2.Length))
            {
                return(false);
            }

            for (int elementIndex = 0; elementIndex < array1.Length; elementIndex++)
            {
                if (!comparison(array1[elementIndex], array2[elementIndex]))
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Registers a custom equality comparer for the specified type.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The Gallio inner comparison engine handles with the case of null objects comparison prior to
        /// the custom comparers. Therefore, while defining a custom comparer, you can safely assume that the
        /// objects to compare are never null.
        /// </para>
        /// </remarks>
        /// <param name="type">The type for which the custom comparer operates.</param>
        /// <param name="equalityComparer">An equality comparer that returns true is the objects are equivalent; false otherwise.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="type"/> or <paramref name="equalityComparer"/> is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown if a custom comparer for the specified type was already registered.</exception>
        public void Register(Type type, EqualityComparison equalityComparer)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            if (equalityComparer == null)
            {
                throw new ArgumentNullException("equalityComparer");
            }

            lock (syncRoot)
            {
                Data data;

                if (equalityComparers.TryGetValue(type, out data))
                {
                    data.Count++;
                }
                else
                {
                    equalityComparers[type] = new Data(equalityComparer);
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Returns a new instance of <see cref="IEqualityComparer{T}"/> using the given
        /// <see cref="EqualityComparison{T}"/> and  <see cref="GetHashCode{T}"/>.
        /// </summary>
        /// <typeparam name="T">The type of the objects to compare.</typeparam>
        /// <param name="equals">The <see cref="EqualityComparison{T}"/> to use for calls of <c>IEqualityComparer&lt;T&gt;.Equals(T, T)</c>.</param>
        /// <param name="getHashCode">The <see cref="GetHashCode{T}"/> to use for calls of <c>IEqualityComparer&lt;T&gt;.GetHashCode(T)</c>.</param>
        /// <returns>A new instance of <see cref="IEqualityComparer{T}"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="equals"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="getHashCode"/> is null.</exception>
        public static IEqualityComparer <T> FromDelegate <T>(EqualityComparison <T> equals, GetHashCode <T> getHashCode)
        {
            Throw.If.Object.IsNull(equals, nameof(equals));
            Throw.If.Object.IsNull(getHashCode, nameof(getHashCode));

            return(new InternalEqualityComparer <T>(equals, getHashCode));
        }
コード例 #4
0
        internal InternalEqualityComparer(EqualityComparison <Object> equals, GetHashCode <Object> getHashCode)
        {
            Throw.If.Object.IsNull(equals, nameof(equals));
            Throw.If.Object.IsNull(getHashCode, nameof(getHashCode));

            _equals      = equals;
            _getHashCode = getHashCode;
        }
コード例 #5
0
        public void Test2()
        {
            EqualityComparison <int> ec = (i1, i2) => i1 == i2;
            var t = ec.ToEqualityComparer();

            Assert.True(t.Equals(1, 1));
            Assert.Equal(1, t.GetHashCode(1));
        }
コード例 #6
0
ファイル: HashBag.cs プロジェクト: renemongeau/NLib
        /// <summary>
        /// Initializes a new instance of the <see cref="HashBag{T}"/> class.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="comparison">The comparer. If null <paramref name="comparer"/> will be use.</param>
        /// <param name="comparer">The comparer. If null <paramref name="comparison"/> will be use.</param>
        /// <exception cref="ArgumentNullException"><paramref name="comparer"/> and <paramref name="comparison"/> are null.</exception>
        protected HashBag(IEnumerable <T> collection, EqualityComparison <T> comparison, IEqualityComparer <T> comparer)
        {
            Check.Current.Requires <ArgumentNullException>(comparer != null || comparison != null, CollectionResource.Initialize_ArgumentNullException_ComparerAndComparison);

            this.equalityComparer = comparison ?? comparer.Equals;
            this.Model            = new Dictionary <T, int>(comparer ?? comparison.ToEqualityComparer());
            this.AddRange(collection);
        }
コード例 #7
0
        public void IsRegisteredFor_should_return_true_for_registered_type()
        {
            var customEqualityComparers = new CustomEqualityComparers();

            customEqualityComparers.Register <Foo>((x, y) => x.Value == y.Value);
            EqualityComparison comparer = customEqualityComparers.Find(typeof(Foo));

            Assert.IsNotNull(comparer);
        }
コード例 #8
0
        /// <summary>
        /// Registers a strongly-typed custom equality comparer for the specified type.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The Gallio inner comparison engine handles with the case of null objects comparison prior to
        /// the custom comparers. Therefore, while defining a custom comparer, you can safely assume that the
        /// objects to compare are never null.
        /// </para>
        /// </remarks>
        /// <typeparam name="T">The type for which the custom comparer operates.</typeparam>
        /// <param name="equalityComparer">An equality comparer that returns true is the objects are equivalent.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="equalityComparer"/> is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown if a custom comparer for the specified type was already registered.</exception>
        public void Register <T>(EqualityComparison <T> equalityComparer)
        {
            if (equalityComparer == null)
            {
                throw new ArgumentNullException("equalityComparer");
            }

            Register(typeof(T), (x, y) => equalityComparer((T)x, (T)y));
        }
コード例 #9
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SortedBag{T}"/> class.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="comparison">The comparer. If null <paramref name="comparer"/> will be use.</param>
        /// <param name="comparer">The comparer. If null <paramref name="comparison"/> will be use.</param>
        /// <exception cref="ArgumentNullException"><paramref name="comparer"/> and <paramref name="comparison"/> are null.</exception>
        protected SortedBag(IEnumerable <T> collection, Comparison <T> comparison, IComparer <T> comparer)
        {
            Check.Current.Requires <ArgumentNullException>(comparer != null || comparison != null, CollectionResource.Initialize_ArgumentNullException_ComparerAndComparison);

            this.currentComparer  = comparison ?? comparer.Compare;
            this.equalityComparer = (x, y) => this.currentComparer(x, y) == 0;
            this.Model            = new SortedDictionary <T, int>(comparer ?? comparison.ToComparer());
            this.AddRange(collection);
        }
コード例 #10
0
        public static T Equal <T>(T item1, T item2, EqualityComparison <T> compare)
        {
            if (!compare(item1, item2))
            {
                throw new ArgumentException(string.Format("The parameters 'item1' and 'item2' are not equal ({0}, {1}).", item1, item2));
            }

            return(item1);
        }
コード例 #11
0
        public void Equals_ok(int foo1, int foo2, bool expectedEqual)
        {
            var customEqualityComparers = new CustomEqualityComparers();

            customEqualityComparers.Register <Foo>((x, y) => x.Value == y.Value);
            EqualityComparison comparer = customEqualityComparers.Find(typeof(Foo));
            bool actualEqual            = comparer(new Foo(foo1), new Foo(foo2));

            Assert.AreEqual(expectedEqual, actualEqual);
        }
コード例 #12
0
 public static int IndexOf <T>(this T[] arr, T val, EqualityComparison <T> comparer)
 {
     for (int ii = 0; ii < arr.GetLength(0); ii++)
     {
         if (comparer.Equals(arr[ii], val))
         {
             return(ii);
         }
     }
     return(-1);
 }
コード例 #13
0
        public void NormalizeCollection_WhenCompareIsNull_Throws()
        {
            List <string> collection = null;

            Gallio.Common.Func <IList <string> > collectionFactory = () => new List <string>();
            Gallio.Common.Func <string, string>  normalize         = x => x + "*";
            EqualityComparison <string>          compare           = null;

            Assert.Throws <ArgumentNullException>(() => NormalizationUtils.NormalizeCollection <IList <string>, string>(
                                                      collection, collectionFactory, normalize, compare));
        }
コード例 #14
0
        /// <summary>
        /// 初始化 <see cref="RegexConst{T}"/> 类的新实例。该实例使用指定的对象作为内部储存的常量对象以及指定的常量正则的值相等性比较方法。
        /// </summary>
        /// <param name="constValue">指定的对象。</param>
        /// <param name="equalityComparison">指定的常量正则的值相等性比较方法。</param>
        /// <exception cref="ArgumentNullException"><paramref name="equalityComparison"/> 的值为 null 。</exception>
        public RegexConst(T constValue, EqualityComparison <T> equalityComparison) : this()
        {
            if (equalityComparison == null)
            {
                throw new ArgumentNullException(nameof(equalityComparison));
            }

            this.constValue = constValue;

            this.equalityComparison = equalityComparison;
            base.condition          = t => equalityComparison(constValue, t);
        }
コード例 #15
0
    /// <summary>
    /// Determines whether two sequences have equal length and elements using the given
    /// function to compare the elements.
    /// </summary>
    /// <typeparam name="T">The element type of the sequences.</typeparam>
    /// <param name="first">The first sequence.</param>
    /// <param name="second">The second sequence.</param>
    /// <param name="equalityComparison">
    /// The function used to compare elements for equality.
    /// </param>
    /// <returns>True if the two sequences have equal length and elements.</returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="first"/> or <paramref name="second"/> is null.
    /// </exception>
    public static bool SequenceEqual <T>(
        this IEnumerable <T> first,
        IEnumerable <T> second,
        EqualityComparison <T>?equalityComparison)
    {
        Requires.NotNull(first);
        Requires.NotNull(second);

        return(System.Linq.Enumerable.SequenceEqual(
                   first,
                   second,
                   EqualityComparer <T> .Create(equalityComparison)));
    }
コード例 #16
0
        public void NormalizeCollection_WhenCollectionIsNull_ReturnsNull()
        {
            List <string> collection = null;

            Gallio.Common.Func <IList <string> > collectionFactory = () => new List <string>();
            Gallio.Common.Func <string, string>  normalize         = x => x + "*";
            EqualityComparison <string>          compare           = ReferenceEquals;

            IList <string> normalizedCollection = NormalizationUtils.NormalizeCollection <IList <string>, string>(
                collection, collectionFactory, normalize, compare);

            Assert.IsNull(normalizedCollection);
        }
コード例 #17
0
        public void NormalizeCollection_WhenAllNormalizedValuesAreUnchanged_ReturnsTheSameCollection()
        {
            IList <string> collection = new[] { "abc", "def", "ghi" };

            Gallio.Common.Func <IList <string> > collectionFactory = () => new List <string>();
            Gallio.Common.Func <string, string>  normalize         = x => x;
            EqualityComparison <string>          compare           = ReferenceEquals;

            IList <string> normalizedCollection = NormalizationUtils.NormalizeCollection <IList <string>, string>(
                collection, collectionFactory, normalize, compare);

            Assert.AreSame(collection, normalizedCollection);
        }
コード例 #18
0
        public void NormalizeCollection_WhenAllNormalizedValuesAreChanged_ReturnsANewCollectionOfNormalizedValues()
        {
            IList <string> collection = new[] { "abc", "def", "ghi" };

            Gallio.Common.Func <IList <string> > collectionFactory = () => new List <string>();
            Gallio.Common.Func <string, string>  normalize         = x => x + "*";
            EqualityComparison <string>          compare           = ReferenceEquals;

            IList <string> normalizedCollection = NormalizationUtils.NormalizeCollection <IList <string>, string>(
                collection, collectionFactory, normalize, compare);

            Assert.AreNotSame(collection, normalizedCollection);
            Assert.AreElementsEqual(new[] { "abc*", "def*", "ghi*" }, normalizedCollection);
        }
コード例 #19
0
        /// <summary>
        /// Adds a matching criterion to the structural equality comparer.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The values returned by the accessor are compared by using the specified comparison delegate.
        /// </para>
        /// </remarks>
        /// <example>
        /// <code><![CDATA[
        /// public class Foo
        /// {
        ///     public int Value;
        /// }
        ///
        /// [TestFixture]
        /// public class FooTest
        /// {
        ///     [Test]
        ///     public void MyTest()
        ///     {
        ///         var foo1 = new Foo() { Value = 123 };
        ///         var foo2 = new Foo() { Value = 123 };
        ///
        ///         Assert.AreEqual(foo1, foo2, new StructuralEqualityComparer<Foo>
        ///         {
        ///             { x => x.Value, (x, y) => x == y },
        ///         });
        ///     }
        /// }
        /// ]]></code>
        /// </example>
        /// <typeparam name="TValue">The type of the value returned by the accessor.</typeparam>
        /// <param name="accessor">An accessor that gets a value from the tested object.</param>
        /// <param name="comparer">A equality comparison delegate to compare the values returned by the accessor, or null to use the default one.</param>
        /// <exception cref="ArgumentNullException">The specified accessor argument is a null reference.</exception>
        public void Add <TValue>(Accessor <T, TValue> accessor, EqualityComparison <TValue> comparer)
        {
            if (accessor == null)
            {
                throw new ArgumentNullException("accessor");
            }

            if (comparer == null)
            {
                comparer = ComparisonSemantics.Default.Equals <TValue>;
            }

            conditions.Add((x, y) => comparer(accessor(x), accessor(y)));
        }
コード例 #20
0
        private static bool EqualsImpl(EqualityComparison <T> predicate, T x, T y)
        {
            if (Object.ReferenceEquals(x, y))
            {
                return(true);
            }

            if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            {
                return(false);
            }

            return(predicate(x, y));
        }
コード例 #21
0
        public override void Evaluate(T value)
        {
            EqualityComparison currentState = value.Equals(Argument.Value)
                ? EqualityComparison.EqualTo
                : EqualityComparison.NotEqualTo;

            if (currentState == Condition &&
                (currentState != lastState || ExecutionMode != ConditionExecutionMode.OnThreshold))
            {
                Event.Fire(value);
            }


            lastState = currentState;
        }
コード例 #22
0
        public static bool SameAll <TSource>(this IEnumerable <TSource> source, EqualityComparison <TSource> equalityComparison)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (equalityComparison == null)
            {
                throw new ArgumentNullException(nameof(equalityComparison));
            }

            TSource first = source.First();

            return(source.All(item => equalityComparison(first, item)));
        }
コード例 #23
0
        /// <summary>
        /// Adds a matching criterion to the structural equality comparer.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The enumerations of values returned by the accessor are compared by using the specified comparer.
        /// </para>
        /// </remarks>
        /// <example>
        /// <code><![CDATA[
        /// public class Foo
        /// {
        ///     public int[] Values;
        /// }
        ///
        /// [TestFixture]
        /// public class FooTest
        /// {
        ///     [Test]
        ///     public void MyTest()
        ///     {
        ///         var foo1 = new Foo() { Values = new int[] { 1, 2, 3, 4, 5 } };
        ///         var foo2 = new Foo() { Values = new int[] { 5, 4, 3, 2, 1 } };
        ///
        ///         Assert.AreEqual(foo1, foo2, new StructuralEqualityComparer<Foo>
        ///         {
        ///             { x => x.Values,
        ///               new StructuralEqualityComparer<int> { { x => x } },
        ///               StructuralEqualityComparerOptions.IgnoreEnumerableOrder
        ///             },
        ///         });
        ///     }
        /// }
        /// ]]></code>
        /// </example>
        /// <typeparam name="TValue">The type of the value returned by the accessor.</typeparam>
        /// <param name="accessor">An accessor that gets an enumeration of values from the tested object.</param>
        /// <param name="comparer">A comparer instance for the values returned by the accessor, or null to use the default one.</param>
        /// <param name="options">Some options indicating how to compare the enumeration of values returned by the accessor.</param>
        /// <exception cref="ArgumentNullException">The specified accessor argument is a null reference.</exception>
        public void Add <TValue>(Accessor <T, IEnumerable <TValue> > accessor, EqualityComparison <TValue> comparer, StructuralEqualityComparerOptions options)
        {
            if (comparer == null)
            {
                comparer = ComparisonSemantics.Default.Equals <TValue>;
            }

            if ((options & StructuralEqualityComparerOptions.IgnoreEnumerableOrder) != 0)
            {
                conditions.Add((x, y) => CompareEnumerablesIgnoringOrder(accessor(x), accessor(y), comparer));
            }
            else
            {
                conditions.Add((x, y) => CompareEnumerables(accessor(x), accessor(y), comparer));
            }
        }
コード例 #24
0
        public static bool Contains <T>(this IEnumerable <T> list, T value, EqualityComparison <T> comparison)
        {
            if (list == null)
            {
                throw new ArgumentNullException();
            }

            foreach (var item in list)
            {
                if (comparison(value, item))
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #25
0
ファイル: Assert.Distinct.cs プロジェクト: kuzeygh/mbunit-v3
        /// <summary>
        /// Verifies that the sequence of objects contains distinct values.
        /// </summary>
        /// <typeparam name="T">The type of value.</typeparam>
        /// <param name="values">The sequence of values to be tested.</param>
        /// <param name="comparer">The comparer to use, or null to use the default one.</param>
        /// <param name="messageFormat">The custom assertion message format, or null if none.</param>
        /// <param name="messageArgs">The custom assertion message arguments, or null if none.</param>
        /// <exception cref="AssertionException">Thrown if the verification failed unless the current <see cref="AssertionContext.AssertionFailureBehavior" /> indicates otherwise.</exception>
        public static void Distinct <T>(IEnumerable <T> values, EqualityComparison <T> comparer, string messageFormat, params object[] messageArgs)
        {
            AssertionHelper.Verify(() =>
            {
                if (comparer == null)
                {
                    comparer = ComparisonSemantics.Default.Equals;
                }

                var duplicates = new List <T>();
                int i          = 0;

                foreach (var value1 in values)
                {
                    int j = 0;

                    foreach (var value2 in values)
                    {
                        if ((i != j) && comparer(value1, value2) && !duplicates.Contains(value1))
                        {
                            duplicates.Add(value1);
                        }

                        j++;
                    }

                    i++;
                }

                if (duplicates.Count > 0)
                {
                    var builder = new AssertionFailureBuilder(
                        "Expected the elements to be distinct but several instances represents the same value.")
                                  .SetMessage(messageFormat, messageArgs);

                    foreach (var duplicate in duplicates)
                    {
                        builder.AddRawLabeledValue("Duplicated Value", duplicate);
                    }

                    return(builder.ToAssertionFailure());
                }

                return(null);
            });
        }
コード例 #26
0
        /// <summary>
        /// Returns true if the elements of both lists are equal.
        /// </summary>
        /// <param name="a">The first collection.</param>
        /// <param name="b">The second collection.</param>
        /// <param name="comparer">The comparison strategy to use.</param>
        /// <returns>True if the elements are equal.</returns>
        public static bool ElementsEqual <T>(IList <T> a, IList <T> b, EqualityComparison <T> comparer)
        {
            int count = a.Count;

            if (count != b.Count)
            {
                return(false);
            }

            for (int i = 0; i < count; i++)
            {
                if (!comparer(a[i], b[i]))
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #27
0
        /// <summary>
        /// Returns a new instance of <see cref="IEqualityComparer{T}"/> using the given implementation of <see cref="IEquatable{T}"/>.
        /// </summary>
        /// <typeparam name="T">The type of the objects to compare.</typeparam>
        /// <returns>A new instance of <see cref="IEqualityComparer{T}"/>.</returns>
        public static IEqualityComparer <T> FromIEquatable <T>()
            where T : IEquatable <T>
        {
            Type   type     = typeof(T);
            Object syncRoot = (_cache as ICollection).SyncRoot;
            IEqualityComparer <T> comparer = null;

            lock (syncRoot) {
                if (_cache.ContainsKey(type))
                {
                    comparer = _cache[type] as IEqualityComparer <T>;
                }
            }

            if (comparer == null)
            {
                EqualityComparison <T> equals = (x, y) => {
                    if (x == null && y == null)
                    {
                        return(true);
                    }

                    if (x != null && y != null)
                    {
                        return(x.Equals(y));
                    }

                    return(false);
                };

                comparer = new InternalEqualityComparer <T>(equals, (obj) => obj.GetHashCode());

                lock (syncRoot) {
                    if (!_cache.ContainsKey(type))
                    {
                        _cache.Add(type, comparer);
                    }
                }
            }

            return(comparer);
        }
コード例 #28
0
        /// <summary>
        /// Verifies that an actual value does not equal some unexpected value according to a particular comparer.
        /// </summary>
        /// <typeparam name="T">The type of value.</typeparam>
        /// <param name="unexpectedValue">The unexpected value.</param>
        /// <param name="actualValue">The actual value.</param>
        /// <param name="comparer">The comparer to use, or null to use the default one.</param>
        /// <param name="messageFormat">The custom assertion message format, or null if none.</param>
        /// <param name="messageArgs">The custom assertion message arguments, or null if none.</param>
        /// <exception cref="AssertionException">Thrown if the verification failed unless the current <see cref="AssertionContext.AssertionFailureBehavior" /> indicates otherwise.</exception>
        public static void AreNotEqual <T>(T unexpectedValue, T actualValue, EqualityComparison <T> comparer, string messageFormat, params object[] messageArgs)
        {
            AssertionHelper.Verify(delegate
            {
                if (comparer == null)
                {
                    comparer = ComparisonSemantics.Default.Equals;
                }

                if (!comparer(unexpectedValue, actualValue))
                {
                    return(null);
                }

                return(new AssertionFailureBuilder("Expected values to be non-equal.")
                       .SetMessage(messageFormat, messageArgs)
                       .AddRawLabeledValuesWithDiffs("Unexpected Value", unexpectedValue, "Actual Value", actualValue)
                       .ToAssertionFailure());
            });
        }
コード例 #29
0
ファイル: Dash.cs プロジェクト: sillsdev/wesay
        private static void RemoveDuplicates(List <Size> result,
                                             Comparison <Size> sortComparer,
                                             EqualityComparison <Size> equalComparer)
        {
            Size prevSize = new Size(int.MaxValue, int.MaxValue);

            result.Sort(sortComparer);
            int i = 0;

            while (i < result.Count)
            {
                if (equalComparer(result[i], prevSize))
                {
                    result.RemoveAt(i);
                }
                else
                {
                    prevSize = result[i];
                    ++i;
                }
            }
        }
コード例 #30
0
        /// <inheritdoc />
        public bool Equals <T>(T left, T right)
        {
            if (Object.ReferenceEquals(left, right))
            {
                return(true);
            }
            if (Object.ReferenceEquals(null, left) ||
                Object.ReferenceEquals(null, right))
            {
                return(false);
            }

            Type leftType = left.GetType();

            if (leftType == right.GetType())
            {
                EqualityComparison comparer = extensionPoints.CustomEqualityComparers.Find(leftType) ?? GetSpecialEqualityFunc(leftType);

                if (comparer != null)
                {
                    return(comparer(left, right));
                }

                if (IsSimpleEnumerableType(leftType))
                {
                    if (IsMultidimensionalArrayType(leftType))
                    {
                        return(CompareMultidimensionalArrays(left as Array, right as Array, CompareEqualsShim) == 0);
                    }

                    var leftEnumerable  = (IEnumerable)left;
                    var rightEnumerable = (IEnumerable)right;
                    return(CompareEnumerables(leftEnumerable, rightEnumerable, CompareEqualsShim) == 0);
                }
            }

            return(left.Equals(right));
        }
コード例 #31
0
ファイル: Dash.cs プロジェクト: bbriggs/wesay
		private static void RemoveDuplicates(List<Size> result,
											 Comparison<Size> sortComparer,
											 EqualityComparison<Size> equalComparer)
		{
			Size prevSize = new Size(int.MaxValue, int.MaxValue);
			result.Sort(sortComparer);
			int i = 0;
			while (i < result.Count)
			{
				if (equalComparer(result[i], prevSize))
				{
					result.RemoveAt(i);
				}
				else
				{
					prevSize = result[i];
					++i;
				}
			}
		}