Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a class versus struct as a dictionary key

Suppose I had the following class and structure definition, and used them each as a key in a dictionary object:

public class MyClass { } public struct MyStruct { }  public Dictionary<MyClass, string> ClassDictionary; public Dictionary<MyStruct, string> StructDictionary;  ClassDictionary = new Dictionary<MyClass, string>(); StructDictionary = new Dictionary<MyStruct, string>(); 

Why is it that this works:

MyClass classA = new MyClass(); MyClass classB = new MyClass(); this.ClassDictionary.Add(classA, "Test"); this.ClassDictionary.Add(classB, "Test"); 

But this crashes on runtime:

MyStruct structA = new MyStruct(); MyStruct structB = new MyStruct(); this.StructDictionary.Add(structA, "Test"); this.StructDictionary.Add(structB, "Test"); 

It says the key already exists, as expected, but only for the struct. The class treats it as two separate entries. I think it has something to do with the data being held as a reference versus value, but I would like a more detailed explanation as to why.

like image 956
Kyle Baran Avatar asked May 09 '13 22:05

Kyle Baran


People also ask

Should I use a class or a struct?

Class instances each have an identity and are passed by reference, while structs are handled and mutated as values. Basically, if we want all of the changes that are made to a given object to be applied the same instance, then we should use a class — otherwise a struct will most likely be a more appropriate choice.

Is it possible to use a custom struct as a dictionary key Swift?

Any type that conforms to the Hashable protocol can be used as a dictionary's Key type, including all of Swift's basic types. You can use your own custom types as dictionary keys by making them conform to the Hashable protocol.

Is dictionary same as struct?

Their intent tends to be different, as revealed by their names: structs are for structured collections of data, while dictionaries are for long lists of named elements.

Can we use class instead of struct?

Class is a reference type, whereas Struct is a value type. A default constructor or destructor cannot be created in Struct. Structs inherit from System. ValueType , cannot be inherited from another Struct or Class, and cannot be a base class.


Video Answer


1 Answers

Dictionary<TKey, TValue> uses an IEqualityComparer<TKey> for comparing the keys. If you do not explicitly specify the comparer when you construct the dictionary, it will use EqualityComparer<TKey>.Default.

Since neither MyClass nor MyStruct implement IEquatable<T>, the default equality comparer will call Object.Equals and Object.GetHashCode for comparing instances. MyClass is derived from Object, so the implementation will use reference equality for comparison. MyStruct on the other hand is derived from System.ValueType (the base class of all structs), so it will use ValueType.Equals for comparing the instances. The documentation for this method states the following:

The ValueType.Equals(Object) method overrides Object.Equals(Object) and provides the default implementation of value equality for all value types in the .NET Framework.

If none of the fields of the current instance and obj are reference types, the Equals method performs a byte-by-byte comparison of the two objects in memory. Otherwise, it uses reflection to compare the corresponding fields of obj and this instance.

The exception occurs because IDictionary<TKey, TValue>.Add throws an ArgumentException if "An element with the same key already exists in the [dictionary]." When using structs, the byte-by-byte comparison done by ValueType.Equals results in both calls attempting to add the same key.

like image 75
Sam Harwell Avatar answered Sep 20 '22 16:09

Sam Harwell