Interchangable Multikey Dictionary - c#

I have many entities that need to share data between themselves. Both entities will request values from this dictionary.
public class Key {
public string nameA;
public string nameB;
}
public class SharedValue {
public int id;
}
private Dictionary<Key, SharedValue> relation = new Dictionary<Key, SharedValue>();
Then adding to the dictionary.
relation.Add(new Key(){ nameA = "User1", nameB = "User2" }, new SharedValue(){ id = -11 });
Finally I was hoping I could get a shared SharedValue no matter of the order of nameA or nameB.
relation[new Key(){ nameA = "User1", nameB = "User2" }].id // Get -11
relation[new Key(){ nameA = "User2", nameB = "User1" }].id // Get -11

Define Equals and GeyHashCode methods for your key class:
public class Key
{
public string nameA;
public string nameB;
public override bool Equals(object obj)
{
return base.Equals(obj as Key);
}
protected bool Equals(Key other)
{
return string.Equals(nameA, other.nameA) && string.Equals(nameB, other.nameB) ||
string.Equals(nameA, other.nameB) && string.Equals(nameB, other.nameA);
}
public override int GetHashCode()
{
return (nameA?.GetHashCode() ^ nameB?.GetHashCode()) ?? 0;
}
}

You could provide a cutom IEqualityComparer<Key> which you can use for the dictionary constructor (and many LINQ methods as well):
public class UnorderedKeyComparer : IEqualityComparer<Key>
{
public bool Equals(Key x, Key y)
{
if (object.ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
if (string.Equals(x.NameA, y.NameA) && string.Equals(x.NameB, y.NameB))
return true;
if (string.Equals(x.NameA, y.NameB) && string.Equals(x.NameB, y.NameA))
return true;
return false;
}
public int GetHashCode(Key obj)
{
return (obj?.NameA?.GetHashCode() ?? int.MinValue) ^ (obj?.NameB?.GetHashCode() ?? int.MinValue);
}
}
So in this case you just need to initialize the dictionary with the UnorderedKeyComparer:
Dictionary<Key, SharedValue> Relation = new Dictionary<Key, SharedValue>(new UnorderedKeyComparer());
By the way, i couldn't resist to fix your naming issues.

You have many options, examples are:
Implement IEqualityComparer<YourKey> and pass an instance of a
class implements IEqualityComparer<YourKey> to the constructor of the
dictionary
Implement IEquatable<T> on your custom key only.
This is how to do Option 2:
public class Key:IEquatable<Key> {
public string nameA;
public string nameB;
public bool Equals(Key other)
{
if(other == null)
return false;
if(ReferenceEquals(this,other))
return true;
return (string.Equals(this.nameA,other.nameA) && string.Equals(this.nameB,other.nameB))
|| (string.Equals(this.nameA,other.nameB) && string.Equals(this.nameB,other.nameA));
}
public override bool Equals(object obj){
if(obj == null)
return false;
if(ReferenceEquals(obj,this))
return true;
return Equals((Key)obj);
}
public override int GetHashCode(){
return (nameA?.GetHashCode() ^ nameB?.GetHashCode()) ?? 0;
}
}
Testing:
private static Dictionary<Key, SharedValue> relation = new Dictionary<Key, SharedValue>();
static void Main(string[] args)
{
relation.Add(new Key{nameA="a",nameB="b"},new SharedValue{id=1});
if(relation.ContainsKey(new Key{nameA="a",nameB="b"})){
Console.WriteLine("YES");
}
if(relation.ContainsKey(new Key{nameA="b",nameB="a"})){
Console.WriteLine("YES");
}
else Console.WriteLine("NO");
}
Output:
YES
YES

Related

Moq function call always returning value even though input doesn't match mocked input values

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.

ContainsKey in dictionary of hashset<myClass>

I have a dictionary:
Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...
And I have:
HashSet<myClass> myHashSet = ...
I want to check if the dictionary (myDict) contains myHashSet.
I tried to override two methods:
1) equal
2) GetHashCode
public class myClass
{
public string id;
public int number;
public override bool Equals(object obj)
{
myClass other = obj as myClass;
bool ret = false;
if (other != null)
{
ret = (this.number == other.number) && (this.id == other.id);
}
return ret;
}
public override int GetHashCode()
{
return this.number ^ this.id.GetHashCode();
}
};
Unfortunately, a key that is found in dictionary, returns false for the code:
myDict.ContainsKey(myHashSet)
Any help appreciated!
Just because you overrode myClass's Equals( and GetHashCode() does not mean that that you overrode HashSet<myClass>'s Equals( and GetHashCode(), that is what is being used when you do the dictionary lookup.
If you want it to work you need to pass a IEqualityComparer<HashSet<myClass>> in to the constructor of the dictionary so it will use that comparer when doing the dictionary lookup.
public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
{
public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(null, x)) return false;
if (ReferenceEquals(null, y)) return false;
return x.SetEquals(y);
}
public int GetHashCode(HashSet<myClass> obj)
{
unchecked
{
int x = 0;
foreach (var myClass in obj)
{
x = (x*397) ^ myClass?.GetHashCode() ?? 0;
}
return x;
}
}
}
//elsewhere
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());
VERY IMPORTANT NOTE: Dictionary keys (and hash sets) break horribly if you do anything that causes Equals( or GetHashCode() to change once put in as the lookup key. If you modify the HashSet<myClass> or one of the myClass objects after you put it in the dictionary you will break the dictionary and potentially the HashSet. See this very good blog post by Eric Lippert on "Guidelines and rules for GetHashCode"
overriding the GetHasCode and Equal is when comparing instances of myClass.
Here's a sample of using ContainsKey, which is checking by objects reference.
Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
var myHashSet = new HashSet<string>();
hashSetDictionary.Add(myHashSet, null);
Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));
Here's an update to your code
public class myClass
{
public myClass(string text, int num)
{
this.Text = text;
this.Num = num;
}
public string Text { get; set; }
public int Num { get; set; }
}
public class MyObj { }
public class AlwaysTrueHashSet<T> : HashSet<T>
{
public override bool Equals(object obj)
{
return this.GetHashCode() == obj.GetHashCode();
}
public override int GetHashCode()
{
return "Counting hashcode".GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,
List<MyObj>>();
var myHashSet1 = new AlwaysTrueHashSet<myClass>();
myHashSet1.Add(new myClass("123", 5));
myDict.Add(myHashSet1, null);
var myHashSet2 = new AlwaysTrueHashSet<myClass>();
myHashSet2.Add(new myClass("123", 5));
/*
* when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
* That's the default behavior.
*
* extend HashSet, and override the gethashcode and equal methods
*/
if (myDict.ContainsKey(myHashSet2))
{
Console.WriteLine("in");
int i = 3; // it doesn't get this line }
}
}
}

C# WPF ComboBox.ObjectCollection.IndexOf Method (Object) can't find Object in ComboBox with an other object with the same value

I have a Combobox which contain IdDataClass object and im tying to find the index of an IdDataClass in my ComboBox with an IdDataClass with the same parameter as the one in the ComboBox.
IdDataClass Instance1 = new IdDataClass(0, "Text");
IdDataClass Instance2 = new IdDataClass(0, "Text");
MyComboBox.Items.Add(Instance1);
int Index = MyComboBox.Items.IndexOf(Instance1);
This example will work and will return the index of ContactClientIdDataClass1
But this one
IdDataClass Instance1 = new IdDataClass(0, "Text");
IdDataClass Instance2 = new IdDataClass(0, "Text");
MyComboBox.Items.Add(Instance1);
int Index = MyComboBox.Items.IndexOf(Instance2);
will not work the value of index is -1. My question is why can't i find the index of instance1 with instance2. They have exactly the same value ?
Ps. I have try to overload the Equals function of my IdDataClass:
public class IdDataClass
{
int _ID;
string _MyData;
public IdDataClass(int ID, string Data)
{
_ID = ID;
_MyData = Data;
}
public bool Equals(IdDataClass p)
{
if ((object)p == null)
{
return false;
}
return (_ID == p._ID)&&(_MyData == p._MyData);
}
}
When you use IndexOf() the method uses Object.Equals() to determine whether two objects are alike. So your own Equals method never gets called because it is not the same method. You have to override the Equals method to obtain the behaviour you want. Add the following lines:
public override bool Equals(object obj)
{
IdDataClass otherObject = obj as IdDataClass;
if (otherObject == null)
return false;
else
return Equals(otherObject );
}
public override int GetHashCode()
{
return _ID.GetHashCode() + _MyData.GetHashCode();
}
Overriding the GetHashCode() should be done as well as you never know how the items are stored within a collection. It maybe uses some kind of HashTable for performance manner. You should make clear that instances that are equal (according to your implementation) return the same hash code.
Try this:
public class IdDataClass : IEquatable<IdDataClass>
{
int _ID;
string _MyData;
public IdDataClass(int ID, string Data)
{
_ID = ID;
_MyData = Data;
}
public bool Equals(IdDataClass p)
{
return (_ID == p._ID) && (_MyData == p._MyData);
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is IdDataClass))
return false;
else
return Equals(obj as IdDataClass);
}
public override int GetHashCode()
{
return _ID.GetHashCode() ^ _MyData.GetHashCode();
}
}
When p is null, this line if ((object)p == null) will throw exception, simple p==null is enough.
_ID, and _MyData are private, so you can't access them like in
return (_ID == p._ID)&&(_MyData == p._MyData);

Linq distinct doesn't call Equals method

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

KeyNotFoundException when it exists

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!

Categories