I have a form responsible of creating (and saving) new Patients. On this form I am using an ErrorProvider to show error icons on invalid fields (in this case just "LastName"). So, as usual => errorProvider.DataSource = patient;
Everything works fine when my model uses default GetHashCode(). But when I try to override this method using a custom hash code (I want to use this model with ISet collections) the control does not work properly. Now, I understand that custom hash codes should be used just for immutable objects. But the point is, how can I fill the fields of these objects if the ErrorProvider behaviour relays on GetHashCode to work properly? Is it necessary to implement a Dirty mechanism that switches between default hash code (during object initialization) and custom hash?
Code sample:
public class Patient : IDataErrorInfo, INotifyPropertyChanged
{
public string lastName;
public virtual string LastName
{
get { return lastName; }
set
{
if (lastName == value) return;
lastName = value;
NotifyPropertyChanged("LastName");
}
}
#region IDataErrorInfo Members
string IDataErrorInfo.Error { get { return null; } }
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
#endregion // IDataErrorInfo Members
protected string GetValidationError(string propertyName)
{
if (ValidatedProperties.IndexOf(propertyName) < 0)
return null;
string error = null;
switch (propertyName)
{
case "LastName":
if (LastName == null)
error = "null";
break;
default:
break;
}
return error;
}
public virtual event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public override int GetHashCode()
{
unchecked
{
int result = 17;
result = 23 * result + ((LastName != null) ? LastName.GetHashCode() : 0);
return result;
}
}
}
Each field that is used in
GetHashCode
function must be immutable. I would not recommend to implement two versions ofGetHashCode
, because it should be persistent and repeatable. I know one possible way how to solve this problem. If you know that some object will be changed, then you can delete it from set before editing operation and add again into set when all modifications are done. In this case you can skip overriding ofGetHashCode
and use SortedSet with a specified comparer that implements IComparer interface.Update
Normally, I would recommend to use
HashSet
if you don't need sorted set as a result.SortedSet
employs binary search tree and it seems that it doesn't useGetHashCode
function.SortedSet
is a bit slower thanHashSet
.SortedSet
performance is about O(log n), because it has to find a space for inserting element in the sorted set. HashSet takes only O(1).IComparer
helps to find whether two objects are equal (there is no need to callEquals
) or tells which of them is less than or greater than other. I wrote a bit of code for testing of SortedSet functionality.Code
Test