可以在类中使用GUID私有属性,以便在GetHashCode覆盖中使用它吗?
就像是:
public class Voucher : IComparable<Voucher>, IComparable, IEquatable<Voucher>
{
private Guid? _guid;
private Guid Guid
{
get
{
return _guid ?? (_guid = Guid.NewGuid()).GetValueOrDefault();
}
}
public int Id { get; private set; }
public string Number { get; private set; }
public DateTime Date { get; private set; }
public Voucher(string number, DateTime date)
{
Number = number;
Date = date;
}
public Voucher(int id, string number, DateTime date)
: this(number, date)
{
Id = id;
}
public override bool Equals(object obj)
{
return Equals(obj as Voucher);
}
public override int GetHashCode()
{
return Guid.GetHashCode();
}
public override string ToString()
{
return String.Format("[{0}] - [{1:dd/MM/yyyy}]", Number, Date);
}
#region IComparable<Voucher> Members
public int CompareTo(Voucher other)
{
if (other == null)
return -1;
if (Date != other.Date)
return Date.CompareTo(other.Date);
else
return Number.CompareTo(other.Number);
}
#endregion
#region IComparable Members
public int CompareTo(object obj)
{
return CompareTo(obj as Voucher);
}
#endregion
#region IEquatable<Voucher> Members
public bool Equals(Voucher other)
{
if (other != null)
return (Number == other.Number) && (Date == other.Date);
return false;
}
#endregion
}
昨天我发现为了覆盖GetHashCode,我们只能使用该类的不可变成员/字段 .
对于我的许多情况,只有通过Sql Server的标识生成的Id和0的新实例 .
因此,对于许多新对象(未持久化到数据库,因此Id为0),对象哈希码是相同的 . 正确?
它会像上面的例子一样使用GUID吗?谢谢 .
EDIT 评论后的课程
所以在您发表评论后我将其更改为:
public class Voucher : IComparable<Voucher>, IComparable, IEquatable<Voucher>
{
public int Id { get; private set; }
public string Number { get; private set; }
public DateTime Date { get; private set; }
public Voucher(string number, DateTime date)
{
Number = number;
Date = date;
}
public Voucher(int id, string number, DateTime date)
: this(number, date)
{
Id = id;
}
public override bool Equals(object obj)
{
return Equals(obj as Voucher);
}
public override int GetHashCode()
{
return Number.GetHashCode() ^ Date.GetHashCode();
}
public override string ToString()
{
return String.Format("[{0}] - [{1:dd/MM/yyyy}]", Number, Date);
}
#region IComparable<Voucher> Members
public int CompareTo(Voucher other)
{
if (other == null)
return -1;
if (Date != other.Date)
return Date.CompareTo(other.Date);
else
return Number.CompareTo(other.Number);
}
#endregion
#region IComparable Members
public int CompareTo(object obj)
{
return CompareTo(obj as Voucher);
}
#endregion
#region IEquatable<Voucher> Members
public bool Equals(Voucher other)
{
if (other != null)
return (Number == other.Number) && (Date == other.Date);
return false;
}
#endregion
}
我想这是可以的,因为凭证是不可变的 .
但是,如果成员编号和日期不是一成不变的,可以访问 - 在课堂外改变?那么解决方案是什么?仅仅记录类“不能在HashCode依赖列表中使用”这样的内容是否足够?
5 回答
不,以这种方式使用
GUID
是不行的,因为它打破了GetHashCode()
的意图,即计算对象内容的散列,如果两个对象具有相同的内容,它们将具有相同的散列 .你应该在这个问题中实现
GetHashCode()
:SO - What is the best algorithm for GetHashCode?你应该考虑哈希对象的全部内容 .上述链接的相关代码是:
正如其他人所提到的,使用Guid是不必要的 . 但我认为我理解在比较未经加工的物体方面的斗争 . 比较对象时我们使用三个级别:
AreSame() =由内存中的相同空间表示 . 我们没有't really use a method here because ' x == y'做得很好 .
AreEqual() =对于我们来说,相等是通过具有相同的Id来定义的,包括0.如果id是default(int),那么我们将其称为'empty' . 我们大部分时间都存在,或者是一个新鲜但尚未持久存在的对象.'re testing for new objects with a method ' IsNullOrEmpty()' which nicely describes an object that either doesn' t存在 .
AreEquivalent() - 这是基于对象的各个属性(例如复合键),并且对象非常主观 . 例如,如果您的号码/日期代表不同的凭证,那么这将用于等效 . 您可以使用匿名对象或其他内容来保持清晰 .
没有 .
Contract 规定两个相等的对象应具有相同的hashCode .
在您的情况下,如果您创建具有相同内容的两个对象,则两个实例的哈希码将不同 . 这打破了 Contract 以及可能依赖于hashCode的组件的行为 .
此外,当您覆盖
GetHashCode()
时,您还必须覆盖Equals(object)
.当覆盖
Equals
和GetHashCode
时,您应遵循的规则是,如果两个实例相等,则它们应具有相同的哈希码 . 您通过为相同的实例创建唯一的哈希码来违反该规则 . 这将导致像Dictionary
和HashSet
这样的集合出现问题,这些集合依赖GetHashCode
为相等的项目返回相同的值 .即使其他所有人都不满意,我也会选择'嗯,这取决于' .
GUID有用的一件事是分布式系统 . 毕竟,它们是全局唯一标识符 - 所以如果你要检查跨多个进程/实例/持久性/等的边界是否相等,并且跨越这些边界传递对象,我会说,你做的是正确的 .
我经常使用(顺序)GUID作为数据库的ID . 虽然大多数DBA由于性能原因不喜欢这种情况,但它的好处是您在插入之前无需检查,从而节省了网络往返 . 就个人而言,我相信这是数据库密钥未来的“最佳实践” . 尽管如此,我承认这是非常有争议的,目前我认为这不是一个好习惯 .
也就是说,你可能不会追求这些事情 . :-)
如果您只想在程序实例中检查是否相等,则应考虑要实现的目标 . 如果要按数据库ID(f.ex.检查冲突)对实例进行分组,则需要使用密钥成员创建相等(在这种情况下ID可能已足够,因为它似乎是1个数据库实例上的数据库记录) .
如果你想在你的应用程序中使用唯一对象,你可以自己实现相等(注意:
Object
的默认实现已经像这样工作) . 这样做的方法是使用RuntimeHelpers.GetHashCode(this)
和Object.ReferenceEquals(this, o);
. 这基本上使用指针进行比较 .总结一下:你're after depends on the implementation. Usually, you want equality because you' re f.ex.填写
Dictionary
或HashSet
. 这还要求您覆盖Equals
和GetHashCode
. 您应该使用的实现是在该上下文中最有意义的实现 .