I have the following class
public class ModInfo : IEquatable<ModInfo>
{
public int ID { get; set; }
public string MD5 { get; set; }
public bool Equals(ModInfo other)
{
return other.MD5.Equals(MD5);
}
public override int GetHashCode()
{
return MD5.GetHashCode();
}
}
I load some data into a list of that class using a method like this:
public void ReloadEverything() {
var beforeSort = new List<ModInfo>();
// Bunch of loading from local sqlite database.
// not included since it's reload boring to look at
var modinfo = beforeSort.OrderBy(m => m.ID).AsEnumerable().Distinct().ToList();
}
Problem is the Distinct() call doesn't seem to do it's job. There are still objects which are equals each other.
Acording to this article: https://msdn.microsoft.com/en-us/library/vstudio/bb348436%28v=vs.100%29.aspx
that is how you are supposed to make distinct work, however it doesn't seem to be calling to Equals method on the ModInfo object.
What could be causing this to happen?
Example values:
modinfo[0]: id=2069, MD5 =0AAEBF5D2937BDF78CB65807C0DC047C
modinfo[1]: id=2208, MD5 = 0AAEBF5D2937BDF78CB65807C0DC047C
I don't care which value gets chosen, they are likely to be the same anyway since the md5 value is the same.
You also need to override Object.Equals, not just implement IEquatable.
If you add this to your class:
public override bool Equals(object other)
{
ModInfo mod = other as ModInfo;
if (mod != null)
return Equals(mod);
return false;
}
It should work.
See this article for more info: Implementing IEquatable Properly
EDIT: Okay, here's a slightly different implementation based on best practices with GetHashCode.
public class ModInfo : IEquatable<ModInfo>
{
public int ID { get; set; }
public string MD5 { get; set; }
public bool Equals(ModInfo other)
{
if (other == null) return false;
return (this.MD5.Equals(other.MD5));
}
public override int GetHashCode()
{
unchecked
{
int hash = 13;
hash = (hash * 7) + MD5.GetHashCode();
return hash;
}
}
public override bool Equals(object obj)
{
ModInfo other = obj as ModInfo;
if (other != null)
{
return Equals(other);
}
else
{
return false;
}
}
}
You can verify it:
ModInfo mod1 = new ModInfo {ID = 1, MD5 = "0AAEBF5D2937BDF78CB65807C0DC047C"};
ModInfo mod2 = new ModInfo {ID = 2, MD5 = "0AAEBF5D2937BDF78CB65807C0DC047C"};
// You should get true here
bool areEqual = mod1.Equals(mod2);
List<ModInfo> mods = new List<ModInfo> {mod1, mod2};
// You should get 1 result here
mods = mods.Distinct().ToList();
What's with those specific numbers in GetHashCode?
Add
public bool Equals(object other)
{
return this.Equals(other as ModInfo)
}
Also see here the recommendations how to implement the equality members: https://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
Related
I am mocking a function call with two arguments.
1. input immutable class object
2. out parameter.
sample code:
Mock<ISample> mockSample = new Mock<ISample>();
SampleClass MyKey = new SampleClass() { prop1 = 1 };
SampleOutput output = new SampleOutput() { prop2 = 2 };
mockSample.setup(s => s.SampleMethod(It.is<SampleKey>(t => t.Equals(MyKey)),
out sampleOut))).Returns(true);
in actual code execution this mocked function return proper value if the key is same as mocked key, However, i am seeing a problem that this mocked function is returning same out value even if key does not match.
Any inputs?
Adding key code:
public class Key
{
public readonly DateTime prop1;
public readonly string prop2;
public Key(DateTime prop1, string prop2)
{
this.prop1 = prop1;
this.prop2 = prop2;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (ReferenceEquals(this, obj))
return true;
Key other = obj as Key;
return this.prop1 == other.prop1 && string.Compare(this.prop2, other.prop2);
}
public override int GetHashCode()
{
return prop1.GetHashCode() ^ prop2.GetHashCode();
}
}
As far as I understood the problem, you need to set up mock on two different behaviors. Please take a look on the example test:
[TestFixture]
public class MoqTests
{
[Test]
public void MoqOutParameter()
{
// Arrange
Mock<ISample> mockSample = new Mock<ISample>();
Key MyKey = new Key(DateTime.Today, "SomeValue");
SampleOutput sampleOut = new SampleOutput() { prop2 = 2 };
mockSample.Setup(s => s.SampleMethod(It.Is<Key>(t => t.Equals(MyKey)),
out sampleOut)).Returns(true);
// Act
SampleOutput out1;
var result1 = mockSample.Object.SampleMethod(new Key(DateTime.Today, "SomeValue"), out out1);
SampleOutput out2;
var result2 = mockSample.Object.SampleMethod(new Key(DateTime.MinValue, "AnotherValue"), out out2);
// Assert
Assert.True(result1);
Assert.AreEqual(out1, sampleOut);
Assert.False(result2);
Assert.Null(out2);
}
}
public class Key
{
public readonly DateTime prop1;
public readonly string prop2;
public Key(DateTime prop1, string prop2)
{
this.prop1 = prop1;
this.prop2 = prop2;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (ReferenceEquals(this, obj))
return true;
Key other = obj as Key;
// was forced to add `== 0` to make it compilable
return this.prop1 == other.prop1 && string.Compare(this.prop2, other.prop2) == 0;
}
public override int GetHashCode()
{
return prop1.GetHashCode() ^ prop2.GetHashCode();
}
}
public class SampleOutput
{
public int prop2 { get; set; }
}
public interface ISample
{
bool SampleMethod(Key key, out SampleOutput sampleOut);
}
UPD: I added classes Key, SampleOutput and interface 'ISample', that I used in this example and also sorrounding class of tests. I am using Nunit for launching test, it must not make sence. You can use any unit testing frame work, you want. This example works for me, the test is green. Please try it out and say what differs from your environment. Also note that I have changed the return line in Key.Equals to make it compilable.
Hope it helps.
I want to use a key (from new instance with the same property) to retrieve value. but it will get KeyNotFoundException.
class Program
{
static void Main(string[] args)
{
Dictionary<Keyclass, ValueClass> dic = new Dictionary<Keyclass, ValueClass>()
{
{ new Keyclass() { Key = "k1" }, new ValueClass() {Value = "v1"} },
{ new Keyclass() { Key = "k2" }, new ValueClass() {Value = "v2"} }
};
var key = new Keyclass() { Key = "k1" };
var value = dic[key];
}
}
public class Keyclass
{
public string Key { get; set; }
}
public class ValueClass
{
public string Value { get; set; }
}
Dictionaries use object.Equals and object.GetHashCode to compare keys so you'll need to implement those in your key class, or provide a IEqualityComparer implementation to the dictionary constructor.
public class Keyclass
{
public string Key { get; set; }
public override bool Equals(object other)
{
var otherKeyClass = other as Keyclass;
return (otherKeyClass != null) && (otherKeyClass.Key == Key);
}
public override int GetHashCode()
{
return Key.GetHashCode();
}
}
As KeyClass is a class, the key is not found, as you create a new object (which has a different reference), even though their properties are the same. Now there are several options:
Overwrite .Equals for the KeyClass, so your two object instances are treated the same and the key can be found.
Instead of creating a new KeyClass instance, get it from the key collection:
var key = dic.Keys.SingleOrDefault(p => p.Key == "k1");
Define KeyClass as a struct instead of class, if possible. Structs are considered equal when all properties are equal.
First of all why aren't you using Dictionary<string,string> instead of using wrapped string ?
Second if you really want to use your wrapper class you have to tell the wrapper class how to compare 2 instances of it by overriding Equals(Keyclass obj) and GetHashCode() Methods :
public override bool Equals(object obj)
{
return this.Key == ((KeyClass)obj).Key;
}
public override int GetHashCode()
{
int hash = 17;
hash = hash * 23 + Key.GetHashCode();
return hash;
}
I hava a type Relation that overrides GetHashCode and Equals.
/// <see cref="System.Object.Equals"/>
public override bool Equals(object obj)
{
bool equals = false;
if (obj is Relation)
{
Relation relation = (Relation)obj;
equals = name.Equals(relation.name);
}
return equals;
}
/// <see cref="System.Object.GetHashCode"/>
public override int GetHashCode()
{
return name.GetHashCode();
}
I have two Relation objects relation1 and relation2.
I have a HashSet<Relation> named relations.
HashSet<Relation> relations = new HashSet<Relation>();
relations.Add(relation1);
The following snippet is supposed to output the hash code of relation1 and relation2.
HashSet<Relation>.Enumerator enumerator = relations.GetEnumerator();
enumerator.MoveNext();
Console.WriteLine(relations.Comparer.GetHashCode(enumerator.Current));
Console.WriteLine(relations.Comparer.GetHashCode(relation2));
The output is:
134042217
134042217
The following snippet compares relation1 and relation2 for equality.
Console.WriteLine(relations.Comparer.Equals(enumerator.Current, relation2));
The output is:
True
However, when I try to determine if the hashSet contains relation2 I get an unexpected result.
relations.Contains(relation2)
The output is:
False
I would expect True.
Here is what I understood from MSDN: in order to determine the presence of an element, Contains is supposed to call GetHashCode first and Equals then. If both methods return True then there is a matching.
Can you give me an explanation ?
This would happen if you changed Name after inserting the first object into the HashSet.
The HashSet recorded the object's original hashcode, which is not the same as the second object.
I wrote a test program with your overrides in it.
internal class Relation
{
public string Name { get; set; }
public override bool Equals(object obj)
{
bool equals = false;
if (obj is Relation)
{
Relation relation = (Relation)obj;
equals = Name.Equals(relation.Name);
}
return equals;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
var relation1 = new Relation() {Name = "Bob"};
var relation2 = new Relation {Name = "Bob"};
var relations = new HashSet<Relation>();
relations.Add(relation1);
var does = relations.Contains(relation2);
// does is now true
}
}
So in the minimal case, your code does what you expect. Therefore I suggest that something else is going on that's causing relation1 and relation2 to not be the same by the time you do the Contains check.
Based on your snippets I wrote the following full sample:
class Program
{
static void Main(string[] args)
{
var r1 = new Relation("name");
var r2 = new Relation("name");
HashSet<Relation> r = new HashSet<Relation>();
r.Add(r1);
bool test = r.Contains(r2);
}
}
class Relation
{
public readonly string Name;
public Relation(string name)
{
Name = name;
}
public override bool Equals(object obj)
{
bool equals = false;
if (obj is Relation)
{
Relation relation = (Relation)obj;
equals = Name.Equals(relation.Name);
}
return equals;
}
/// <see cref="System.Object.GetHashCode"/>
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
The value of 'test' is true. The only way I can explain the difference in behaviour between your code and this sample is that the Name property must not be the same between the two objects at the time that you perform the Contains check.
I'm getting the first key in a dictionary and comparing it with a lookup value. They are the same, but when I try to access the key from the dictionary I get a KeyNotFoundException:
public void Draw(Graphics graphics, Shape shape)
{
foreach (var line in shape.Lines)
{
var tuple = shape.LinesToNurmalDictionary.Keys.First();
bool equals = tuple == line;
bool referenceEquals = ReferenceEquals(tuple, line);
var invisible = shape.LinesToNurmalDictionary[line].All(x => x.Z < 0);
How can I fix it?
Added:
Dictionary is
Dictionary<Tuple<ShapePoint, ShapePoint>, List<ShapePoint>> LinesToNurmalDictionary;
where ShapePoint is a class
So i 'solved' my problem by using my own class instead of Tuple, but actualy question still unresponsed:
public class Line
{
public ShapePoint A { get; set; }
public ShapePoint B { get; set; }
public List<ShapePoint> Normals { get; set; }
public Line(ShapePoint a, ShapePoint b)
{
A = a;
B = b;
Normals = new List<ShapePoint>();
}
private sealed class DefaultEqualityComparer : IEqualityComparer<Line>
{
public bool Equals(Line x, Line y)
{
if (ReferenceEquals(x, y))
return true;
if (ReferenceEquals(x, null))
return false;
if (ReferenceEquals(y, null))
return false;
if (x.GetType() != y.GetType())
return false;
return Equals(x.A, y.A) && Equals(x.B, y.B);
}
public int GetHashCode(Line obj)
{
unchecked
{
return ((obj.A != null ? obj.A.GetHashCode() : 0)*397) ^ (obj.B != null ? obj.B.GetHashCode() : 0);
}
}
}
private static readonly IEqualityComparer<Line> DefaultComparerInstance = new DefaultEqualityComparer();
public static IEqualityComparer<Line> DefaultComparer
{
get
{
return DefaultComparerInstance;
}
}
}
As tia already said in a comment, this happens because an entry is first added to the Dictionary<,> where the hash code of the key (here the Tuple<ShapePoint, ShapePoint>) has some value which is "saved" and kept by the Dictionary<,>. After that the key object is "mutated" (modified) in a way that changes its hash code. This leads to the Dictionary<,> being in a corrupt state.
Therefore when the key is searched for afterwards, it is not found. Its "new" hash code differs from the hash the Dictionary<,> thinks this key has.
Do not modify objects that might be keys in a Dictionary<,> (or members of a HashSet<> and so on) in a way that changes their hash codes.
Here's an example illustrating. The type:
class Changeable
{
public int Prop { get; set; }
public override int GetHashCode()
{
return Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as Changeable);
}
public bool Equals(Changeable other)
{
if (other == null)
return false;
return GetType() == other.GetType() && Prop == other.Prop;
}
}
The code that gives the same problem:
var onlyInstance = new Changeable();
var dict = new Dictionary<Changeable, string>();
onlyInstance.Prop = 1;
dict.Add(onlyInstance, "what-ever");
onlyInstance.Prop = 2;
string restoredValue = dict[onlyInstance]; // throws!
I'm looking at how build the best HashCode for a class and I see some algorithms. I saw this one : Hash Code implementation, seems to be that .NET classes HashCode methods are similar (see by reflecting the code).
So question is, why don't create the above static class in order to build a HashCode automatically, just by passing fields we consider as a "key".
// Old version, see edit
public static class HashCodeBuilder
{
public static int Hash(params object[] keys)
{
if (object.ReferenceEquals(keys, null))
{
return 0;
}
int num = 42;
checked
{
for (int i = 0, length = keys.Length; i < length; i++)
{
num += 37;
if (object.ReferenceEquals(keys[i], null))
{ }
else if (keys[i].GetType().IsArray)
{
foreach (var item in (IEnumerable)keys[i])
{
num += Hash(item);
}
}
else
{
num += keys[i].GetHashCode();
}
}
}
return num;
}
}
And use it as like this :
// Old version, see edit
public sealed class A : IEquatable<A>
{
public A()
{ }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Value { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as A);
}
public bool Equals(A other)
{
if(object.ReferenceEquals(other, null))
? false
: Key1 == other.Key1 && Key2 == other.Key2;
}
public override int GetHashCode()
{
return HashCodeBuilder.Hash(Key1, Key2);
}
}
Will be much simpler that always is own method, no? I'm missing something?
EDIT
According all remarks, I got the following code :
public static class HashCodeBuilder
{
public static int Hash(params object[] args)
{
if (args == null)
{
return 0;
}
int num = 42;
unchecked
{
foreach(var item in args)
{
if (ReferenceEquals(item, null))
{ }
else if (item.GetType().IsArray)
{
foreach (var subItem in (IEnumerable)item)
{
num = num * 37 + Hash(subItem);
}
}
else
{
num = num * 37 + item.GetHashCode();
}
}
}
return num;
}
}
public sealed class A : IEquatable<A>
{
public A()
{ }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Value { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as A);
}
public bool Equals(A other)
{
if(ReferenceEquals(other, null))
{
return false;
}
else if(ReferenceEquals(this, other))
{
return true;
}
return Key1 == other.Key1
&& Key2 == other.Key2;
}
public override int GetHashCode()
{
return HashCodeBuilder.Hash(Key1, Key2);
}
}
Your Equals method is broken - it's assuming that two objects with the same hash code are necessarily equal. That's simply not the case.
Your hash code method looked okay at a quick glance, but could actually do some with some work - see below. It means boxing any value type values and creating an array any time you call it, but other than that it's okay (as SLaks pointed out, there are some issues around the collection handling). You might want to consider writing some generic overloads which would avoid those performance penalties for common cases (1, 2, 3 or 4 arguments, perhaps). You might also want to use a foreach loop instead of a plain for loop, just to be idiomatic.
You could do the same sort of thing for equality, but it would be slightly harder and messier.
EDIT: For the hash code itself, you're only ever adding values. I suspect you were trying to do this sort of thing:
int hash = 17;
hash = hash * 31 + firstValue.GetHashCode();
hash = hash * 31 + secondValue.GetHashCode();
hash = hash * 31 + thirdValue.GetHashCode();
return hash;
But that multiplies the hash by 31, it doesn't add 31. Currently your hash code will always return the same for the same values, whether or not they're in the same order, which isn't ideal.
EDIT: It seems there's some confusion over what hash codes are used for. I suggest that anyone who isn't sure reads the documentation for Object.GetHashCode and then Eric Lippert's blog post about hashing and equality.
This is what I'm using:
public static class ObjectExtensions
{
/// <summary>
/// Simplifies correctly calculating hash codes based upon
/// Jon Skeet's answer here
/// http://stackoverflow.com/a/263416
/// </summary>
/// <param name="obj"></param>
/// <param name="memberThunks">Thunks that return all the members upon which
/// the hash code should depend.</param>
/// <returns></returns>
public static int CalculateHashCode(this object obj, params Func<object>[] memberThunks)
{
// Overflow is okay; just wrap around
unchecked
{
int hash = 5;
foreach (var member in memberThunks)
hash = hash * 29 + member().GetHashCode();
return hash;
}
}
}
Example usage:
public class Exhibit
{
public virtual Document Document { get; set; }
public virtual ExhibitType ExhibitType { get; set; }
#region System.Object
public override bool Equals(object obj)
{
return Equals(obj as Exhibit);
}
public bool Equals(Exhibit other)
{
return other != null &&
Document.Equals(other.Document) &&
ExhibitType.Equals(other.ExhibitType);
}
public override int GetHashCode()
{
return this.CalculateHashCode(
() => Document,
() => ExhibitType);
}
#endregion
}
Instead of calling keys[i].GetType().IsArray, you should try to cast it to IEnumerable (using the as keyword).
You can fix the Equals method without repeating the field list by registering a static list of fields, like I do here using a collection of delegates.
This also avoids the array allocation per-call.
Note, however, that my code doesn't handle collection properties.