You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
5.8 KiB
144 lines
5.8 KiB
5 years ago
|
#if NET20 || NET30 || NET35 || !NET_4_6
|
||
|
|
||
|
using System.Collections.Generic;
|
||
|
using LinqInternal.Core;
|
||
|
|
||
|
namespace System.Collections
|
||
|
{
|
||
|
public static class StructuralComparisons
|
||
|
{
|
||
|
private static readonly InternalComparer _comparer = new InternalComparer();
|
||
|
|
||
|
public static IComparer StructuralComparer
|
||
|
{
|
||
|
get { return _comparer; }
|
||
|
}
|
||
|
|
||
|
public static IEqualityComparer StructuralEqualityComparer
|
||
|
{
|
||
|
get { return _comparer; }
|
||
|
}
|
||
|
|
||
|
private sealed class InternalComparer : IComparer, IEqualityComparer
|
||
|
{
|
||
|
int IComparer.Compare(object x, object y)
|
||
|
{
|
||
|
var comparable = x as IStructuralComparable;
|
||
|
if (comparable != null)
|
||
|
{
|
||
|
return comparable.CompareTo(y, this);
|
||
|
}
|
||
|
return Comparer.Default.Compare(x, y);
|
||
|
}
|
||
|
|
||
|
bool IEqualityComparer.Equals(object x, object y)
|
||
|
{
|
||
|
bool result;
|
||
|
if (NullComparison(x, y, out result))
|
||
|
{
|
||
|
return result;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var comparable = x as IStructuralEquatable;
|
||
|
if (comparable != null)
|
||
|
{
|
||
|
return comparable.Equals(y, this);
|
||
|
}
|
||
|
var typeX = x.GetType();
|
||
|
var typeY = x.GetType();
|
||
|
if (typeX.IsArray && typeY.IsArray)
|
||
|
{
|
||
|
if (typeX.GetElementType() == typeY.GetElementType())
|
||
|
{
|
||
|
CheckRank(x, y, typeX, typeY);
|
||
|
var xLengthInfo = typeX.GetProperty("Length");
|
||
|
var yLengthInfo = typeY.GetProperty("Length");
|
||
|
if ((int)xLengthInfo.GetValue(x, TypeHelper.EmptyObjects) != (int)yLengthInfo.GetValue(y, TypeHelper.EmptyObjects))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var xEnumeratorInfo = typeX.GetMethod("GetEnumerator");
|
||
|
var yEnumeratorInfo = typeX.GetMethod("GetEnumerator");
|
||
|
IEnumerator firstEnumerator = null;
|
||
|
IEnumerator secondEnumerator = null;
|
||
|
var comparer = this as IEqualityComparer;
|
||
|
try
|
||
|
{
|
||
|
firstEnumerator = (IEnumerator)xEnumeratorInfo.Invoke(x, TypeHelper.EmptyObjects);
|
||
|
secondEnumerator = (IEnumerator)yEnumeratorInfo.Invoke(y, TypeHelper.EmptyObjects);
|
||
|
while (firstEnumerator.MoveNext())
|
||
|
{
|
||
|
if (!secondEnumerator.MoveNext())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (!comparer.Equals(firstEnumerator.Current, secondEnumerator.Current))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return !secondEnumerator.MoveNext();
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
var disposableX = firstEnumerator as IDisposable;
|
||
|
if (disposableX != null)
|
||
|
{
|
||
|
disposableX.Dispose();
|
||
|
}
|
||
|
var disposableY = secondEnumerator as IDisposable;
|
||
|
if (disposableY != null)
|
||
|
{
|
||
|
disposableY.Dispose();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return EqualityComparer<object>.Default.Equals(x, y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int IEqualityComparer.GetHashCode(object obj)
|
||
|
{
|
||
|
var comparer = obj as IStructuralEquatable;
|
||
|
if (comparer != null)
|
||
|
{
|
||
|
return comparer.GetHashCode(this);
|
||
|
}
|
||
|
return EqualityComparer<object>.Default.GetHashCode(obj);
|
||
|
}
|
||
|
|
||
|
private static void CheckRank(object x, object y, Type typeX, Type typeY)
|
||
|
{
|
||
|
var xRankInfo = typeX.GetProperty("Rank");
|
||
|
var yRankInfo = typeY.GetProperty("Rank");
|
||
|
if ((int)xRankInfo.GetValue(x, TypeHelper.EmptyObjects) != 1)
|
||
|
{
|
||
|
throw new ArgumentException("Only one-dimensional arrays are supported", "x");
|
||
|
}
|
||
|
if ((int)yRankInfo.GetValue(y, TypeHelper.EmptyObjects) != 1)
|
||
|
{
|
||
|
throw new ArgumentException("Only one-dimensional arrays are supported", "y");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static bool NullComparison(object x, object y, out bool result)
|
||
|
{
|
||
|
var xNull = ReferenceEquals(x, null);
|
||
|
var yNull = ReferenceEquals(y, null);
|
||
|
result = xNull == yNull;
|
||
|
return xNull || yNull;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|