我在寻找相同问题的解决方案时遇到了您的问题。这是我正在尝试的解决方案,看看它是否满足您的需求:
首先,我所有的 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();
}
}
我创建了一个在 GetHashCode() 覆盖中使用的只读 Guid 字段。这将确保如果我将派生的 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)方法中,空对象显然不相等,同样的引用显然是,那么我们只需要检查ID是否== 0,如果是,我们就说两个相同类型的对象两者都具有 0 的 ID 不相等。否则,如果它们的属性都相同,我们将说它们相等。
我认为这涵盖了所有相关情况,但如果我不正确,请插话。希望这可以帮助。
=== 编辑 1
我在想我的 GetHashCode() 不对,我查看了有关该主题的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 可能会更改(不想要孤儿)。这将满足上面链接答案中对平等的约束。