我有一個從繼承自IEquatable的基類繼承的對象<>。到目前爲止這麼好,它適用於繼承相同基類的其他對象。但是當我使用「Attrbiutes」屬性時,我有類「RoomType」,在那裏似乎有問題。下面你會看到這些類和一個測試,我期望得到其他輸出。IEquatable對象上的LINQ.Distinct不起作用
當我註釋「SafeHashCode(Attributes)」返回預期結果時,我將問題縮小到了RoomType.GetHashCode()。
測試:
private static void QuickTest()
{
RoomType[] rooms = new RoomType[] {
new RoomType {
Attributes = new [] { "a", "b,"c"},
},
new RoomType
{
Attributes = new [] { "a", "b","c"},
}
};
List<RoomType> result = rooms.Distinct().ToList();
//result contains 2 items, I was expecting 1
}
RoomType:
public class RoomType : EntityBase
{
public string OriginalRoomCode { get; set; }
public Enum.RoomType RoomCode { get; set; }
public IEnumerable<string> Attributes { get; set; }
public override bool Equals(object obj)
{
RoomType other = obj as RoomType;
if (other != null)
return Equals(other);
return false;
}
public override bool Equals(EntityBase obj)
{
RoomType y = (RoomType)obj;
return SafeEqual(OriginalRoomCode, y.OriginalRoomCode) &&
SafeEqual(RoomCode, y.RoomCode) &&
SafeEqual(Attributes,y.Attributes);
}
public override int GetHashCode()
{
unchecked
{
return SafeHashCode(OriginalRoomCode)^
SafeHashCode(RoomCode)^
SafeHashCode(Attributes);
}
}
public override object Clone()
{
return new RoomType
{
RoomCode = (Enum.RoomType)SafeClone(RoomCode),
OriginalRoomCode = (string)SafeClone(OriginalRoomCode),
Attributes = (IEnumerable<string>)SafeClone(Attributes)
};
}
}
EntityBase:
public abstract class EntityBase : IEquatable<EntityBase>, ICloneable
{
public bool SafeEqual<T>(T x, T y)
{
bool isXDefault = EqualityComparer<T>.Default.Equals(x, default(T));
bool isYDefault = EqualityComparer<T>.Default.Equals(y, default(T));
if (isXDefault && isYDefault)
return true;
if (isXDefault != isYDefault)
return false;
if (x is EntityBase)
return x.Equals(y);
IEnumerable<object> xEnumerable = x as IEnumerable<object>;
IEnumerable<object> yEnumerable = y as IEnumerable<object>;
if (xEnumerable != null && yEnumerable != null)
{
foreach (var yItem in yEnumerable)
{
bool match = false;
foreach (var xItem in xEnumerable)
{
if(SafeEqual(xItem, yItem))
{
match = true;
break;
}
}
if (!match)
return false;
}
return true;
}
return x.Equals(y);
}
public int SafeHashCode<T>(T x)
{
if (EqualityComparer<T>.Default.Equals(x, default(T)))
return 0;
return x.GetHashCode();
}
public object SafeClone<T>(T x)
{
//if x is null or default value
if (EqualityComparer<T>.Default.Equals(x, default(T)))
return default(T);
//if x is of type EntityBase call clone()
if (x is EntityBase)
return (x as EntityBase).Clone();
//else the type is a default type return the value
return x;
}
public abstract bool Equals(EntityBase other);
public override abstract int GetHashCode();
public abstract override bool Equals(object obj);
public abstract object Clone();
}
更新 我能夠通過增加內SafeHashCode下面的代碼來修復它(T x)
IEnumerable<object> xEnumerable = x as IEnumerable<object>;
if (xEnumerable != null)
return xEnumerable.Aggregate(17, (acc, item) => acc * 19 + SafeHashCode(item));
顯然'SaveHashCode'(你的意思是'Safe'?)不具有可枚舉正常工作(返回默認'GetHashCode'實現) –
你說得對,我彪安全(更新它的時候了:) ) – BvdVen
解決它的一種方法是插入'if(typeof(T)!= typeof(string)&& typeof(IEnumerable).IsAssignableFrom(typeof(T)))return 0;' –