网上演练
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

#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