Is it OK to have a GUID private property in a class in order to use it in GetHashCode override?
Something like:
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
}
Yesterday I found out that in order to override GetHashCode we have to use only immutable members/fields of the class.
For many of my cases that is only the Id that is produced by identity of the Sql Server and for new instances that is 0.
So for many new objects (not persisted to database thus Id is 0) object hash code is the same. Correct?
Would it be a solution to use GUID like the example above? Thanks.
EDIT Class after comments
So after your comments I've changed it to:
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
}
I guess that this is OK since Voucher is immutable.
But if members Number and Date were not immutable and could be accessed - altered outside the class? Then what is the solution? Is it enough just to document the class something like "Cannot be used in HashCode depended Lists"?