1 //---------------------------------------------------------------------
2 // <copyright file="ByValueEqualityComparer.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections;
12 using System.Collections.Generic;
14 using System.Diagnostics;
17 namespace System.Data.Common.Utils
20 /// An implementation of IEqualityComparer<object> that compares byte[] instances by value, and
21 /// delegates all other equality comparisons to a specified IEqualityComparer. In the default case,
22 /// this provides by-value comparison for instances of the CLR equivalents of all EDM primitive types.
24 internal sealed class ByValueEqualityComparer : IEqualityComparer<object>
27 /// Provides by-value comparison for instances of the CLR equivalents of all EDM primitive types.
29 internal static readonly ByValueEqualityComparer Default = new ByValueEqualityComparer();
31 private ByValueEqualityComparer()
35 public new bool Equals(object x, object y)
37 if (object.Equals(x, y))
42 // If x and y are both non-null byte arrays, then perform a by-value comparison
43 // based on length and element values, otherwise defer to the default comparison.
45 byte[] xBytes = x as byte[];
46 byte[] yBytes = y as byte[];
47 if (xBytes != null && yBytes != null)
49 return CompareBinaryValues(xBytes, yBytes);
55 public int GetHashCode(object obj)
59 byte[] bytes = obj as byte[];
62 return ComputeBinaryHashCode(bytes);
70 return obj.GetHashCode();
73 internal static int ComputeBinaryHashCode(byte[] bytes)
75 Debug.Assert(bytes != null, "Byte array cannot be null");
77 for (int i = 0, n = Math.Min(bytes.Length, 7); i < n; i++)
79 hashCode = ((hashCode << 5) ^ bytes[i]);
84 internal static bool CompareBinaryValues(byte[] first, byte[] second)
86 Debug.Assert(first != null && second != null, "Arguments cannot be null");
88 if (first.Length != second.Length)
93 for (int i = 0; i < first.Length; i++)
95 if (first[i] != second[i])
106 /// Extends IComparer support to the (non-IComparable) byte[] type, based on by-value comparison.
108 internal class ByValueComparer : IComparer
110 internal static readonly IComparer Default = new ByValueComparer(Comparer<object>.Default);
112 private readonly IComparer nonByValueComparer;
113 private ByValueComparer(IComparer comparer)
115 Debug.Assert(comparer != null, "Non-ByValue comparer cannot be null");
116 this.nonByValueComparer = comparer;
119 int IComparer.Compare(object x, object y)
121 if (object.ReferenceEquals(x, y))
127 //We can convert DBNulls to nulls for the purposes of comparison.
128 Debug.Assert(!((object.ReferenceEquals(x, DBNull.Value)) && (object.ReferenceEquals(y,DBNull.Value))), "object.ReferenceEquals should catch the case when both values are dbnull");
129 if (object.ReferenceEquals(x, DBNull.Value))
133 if (object.ReferenceEquals(y, DBNull.Value))
138 if (x != null && y != null)
140 byte[] xAsBytes = x as byte[];
141 byte[] yAsBytes = y as byte[];
142 if (xAsBytes != null && yAsBytes != null)
144 int result = xAsBytes.Length - yAsBytes.Length;
148 while (result == 0 && idx < xAsBytes.Length)
150 byte xVal = xAsBytes[idx];
151 byte yVal = yAsBytes[idx];
154 result = xVal - yVal;
163 return this.nonByValueComparer.Compare(x, y);