Derek
Derek

Reputation: 8630

C# Dictionaries - Custom Objects

I've never used Dictionaries before, and I'm just looking to learn more about them.

I'm a bit lost when it comes to Custom Objects. Is it possible to use a custom object like the class below, as the Key, rather than the value?

class Car
    {
        public Car(int id, string model)
        {
            ID = id;
            Model = model;
        }

        public int ID { get; private set; }
        public string Model { get; private set; }
    }

If you where to create a Dictionary, Like this :-

 Dictionary<Car, bool> Cars = new Dictionary<Car, bool>();

How would you use the Car object as a Key, when searching the Dictionaries contents?

Upvotes: 1

Views: 3627

Answers (6)

Novice
Novice

Reputation: 2487

var car1 = new Car(1,"A300");
var car2 = new Car(1,"A400");

Adding to a dictionary

   Cars.Add(car1 ,true);
   Cars.Add(car2 ,true);
   Cars.ContainsKey(car1) - //which returns boolean can be used to check for the exisitence of a key

To get the value you can use

   var x=Cars[car1];

Using a key which is not in the dictionary collection will throw an exception.

Upvotes: 1

Shrinand
Shrinand

Reputation: 351

In your situation you are trying to use your custom object as a key in the dictionary, in dictionary data structure each key is unique, so you need to provide a way in your data structure to differentiate one object from other.

This is done by overriding GetHashCode() method, implementing IEquatable is optional but it brings clarity to what you are trying to do.

class Car : IEquatable<Car>
    {
        public Car(int id, string model)
        {
            ID = id;
            Model = model;
        }

        public int ID { get; private set; }
        public string Model { get; private set; }

        public bool Equals(Car other)
        {
            return !ReferenceEquals(null, other) && ID == other.ID;
        }
// This is a must if you like to correctly use your object as a key in dictionary
        public override int GetHashCode()
        {
            return ID.GetHashCode();
        }
    }

Upvotes: 1

A-Dubb
A-Dubb

Reputation: 1709

You need to implement Equals() and GetHashCode() for the Car type. Since Car is a reference type, you could potentially put a difference instance of the same Car (Id property for both Car instances matches, but they point to different objects) in the dictionary and not even be aware.

You don't want this to be possible

var carMap = new Dictionary<Car, string>();

var carOne = new Car { Id = 1 };
var careTwo = new Car { Id = 1 };

carMap[carOne] = "one";

// you want this line to fail since a Car with this Id is already present
carMap[carTwo] = "two";

for GetHasCode(), you can return Id.GetHashCode()

for Equals(), just do the standard boilerplate checks like checking that the types are the same, etc.

This link provides more detail about why you should implement GetHashCode()

Upvotes: 3

sim1
sim1

Reputation: 720

From MSDN: (http://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.80).aspx)

If type TKey implements the System.IEquatable generic interface, the default equality comparer uses that implementation.

So in your case you need to implement IEquatable<Car>, for example:

   class Car : IEquatable<Car>
    {
        public Car(int id, string model)
        {
            ID = id;
            Model = model;
        }

        public int ID { get; private set; }
        public string Model { get; private set; }

        public bool Equals(Car other)
        {
            return this.ID == other.ID;
        }
    }

Upvotes: 2

Bobson
Bobson

Reputation: 13696

Yes, this is quite possible, but there's a very important caveat to be aware of.

Dictionaries check keys using default equality comparison. For custom class objects, that means "Is this a reference to the same object". Not "Is this an object with the same data".

So for example:

var car1 = new Car(1, "Avalon");
var car2 = car1;
var car3 = new Car(1, "Avalon");

Cars.Add(car1, true);
Console.WriteLine(Cars[car2]); // writes "True";
Console.WriteLine(Cars[car3]); // throws a KeyNotFoundException

You can resolve this by overriding GetHashValue() and Equals() for your class. See here.

Upvotes: 3

Servy
Servy

Reputation: 203814

To use an object as the key of a Dictionary it's important for it to have implementations of Equals and GetHashCode that properly define what "equality" means for your object.

The default implementations of those two methods is usually not appropriate, as by default they will just compare the references, meaning two different objects with the same values won't be "equal", when you probably want them to be.

Once you have sensible implementations of those methods, you can use the dictionaries indexer to put a Car instance in, and get the boolean value associated with that Car.

Upvotes: 2

Related Questions