我在寻找同一问题的解决方案时遇到了您的问题。这是我正在尝试的解决方案,看看它是否满足您的需求:
首先,我所有的 POCO 都源自这个抽象类:
public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
private readonly Guid _guid = Guid.NewGuid();
#region IEquatable<T> Members
public abstract bool Equals(T other);
#endregion
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof (T))
{
return false;
}
return Equals((T)obj);
}
public override int GetHashCode()
{
return _guid.GetHashCode();
}
}
我创建了一个只读 Guid 字段,并在 GetHashCode() 覆盖中使用它。这将确保如果我将派生的 POCO 放入字典或其他使用哈希的东西中,如果我在此期间调用 .SaveChanges() 并且 ID 字段由基类更新,我不会孤立它这是我不确定是否完全正确的一部分,或者它是否比 Base.GetHashCode() 更好?。我抽象了 Equals(T other) 方法,以确保实现类必须以某种有意义的方式实现它,最有可能使用 ID 字段。我将 Equals(object obj) 重写放在这个基类中,因为它对于所有派生类可能也是相同的。
这将是抽象类的实现:
public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }
public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
}
ID 属性被设置为数据库中的主键,EF 知道这一点。新创建的对象上的 ID 为 0,然后在 .SaveChanges() 上设置为唯一的正整数。所以在重写的 Equals(Species other) 方法中,null 对象显然不相等,相同的引用显然相等,那么我们只需要检查 ID == 0 即可。如果是,我们会说两个相同类型的对象两者的 ID 均为 0 并不相等。否则,如果它们的属性都相同,我们就会说它们相等。
我认为这涵盖了所有相关情况,但如果我不正确,请指出。希望这可以帮助。
===编辑1
我认为我的 GetHashCode() 不正确,然后我看了这个https://stackoverflow.com/a/371348/213169 https://stackoverflow.com/a/371348/213169回答有关该主题的问题。上面的实现违反了返回 Equals() == true 的对象必须具有相同哈希码的约束。
这是我的第二次尝试:
public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
#region IEquatable<T> Members
public abstract bool Equals(T other);
#endregion
public abstract override bool Equals(object obj);
public abstract override int GetHashCode();
}
以及实施:
public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }
public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as Species);
}
public override int GetHashCode()
{
unchecked
{
return ((LegacyCode != null ? LegacyCode.GetHashCode() : 0) * 397) ^
(Name != null ? Name.GetHashCode() : 0);
}
}
public static bool operator ==(Species left, Species right)
{
return Equals(left, right);
}
public static bool operator !=(Species left, Species right)
{
return !Equals(left, right);
}
}
所以我去掉了基类中的Guid,并将GetHashCode移到了实现中。我将 Resharper 的 GetHashCode 实现与除 ID 之外的所有属性一起使用,因为 ID 可能会更改(不希望出现孤儿)。这将满足上面链接答案中对平等的约束。