2013-02-26 46 views
1

我从来没有用过字典,我只是想更多地了解它们。C#字典 - 自定义对象

当谈到自定义对象时,我有点失落。是否可以像下面的类一样使用自定义对象作为Key而不是值?

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

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

如果您在何处创建一个字典,像这样: -

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

你会如何使用Car对象作为重点,搜索字典内容时?

+1

德里克这里是一个很好的链接,就如何解释工作http://www.dotnetperls.com/collections – MethodMan 2013-02-26 16:41:14

+0

对于这样一个简单的数据结构中读取,你可以改变“类”到“结构”和平等将按预期工作。尽管如此,我不会那么做。 – Scroog1 2013-02-26 16:50:41

+0

@ Scroog1 - 切换到一个'struct'完全改变了字典的行为,因为结构体*被按值比较。 – Bobson 2013-02-26 17:13:59

回答

1

在你的情况,你要使用你的自定义对象作为字典中的关键字,在字典数据结构中,每个关键字都是唯一的,所以您需要在数据结构中提供一种方法来区分一个对象与其他对象。

这是通过重写的GetHashCode()方法来完成,实现IEquatable是可选的,但是它带来的清晰度你正在尝试做的。

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(); 
     } 
    } 
+0

感谢大家的帮助,一个本,它现在更清楚! – Derek 2013-02-27 08:45:14

2

要使用一个对象作为Dictionary的关键字,请务必使用EqualsGetHashCode的实现来正确定义对象的“相等”含义。

这两种方法的默认实现通常是不恰当的,因为默认情况下,他们将只是比较引用,这意味着有相同的价值观两个不同的对象会不会是“平等”的时候,你可能想的那样。

一旦您明智地实现了这些方法,您可以使用字典索引器来放入一个Car实例,并获取与该Car关联的布尔值。

3

是的,这是很有可能的,但有一个非常重要的警告要注意。

词典检查密钥使用默认相等比较。对于自定义类对象,这意味着“这是对相同对象的引用”。不是“这是一个具有相同数据的对象”。

因此,例如:

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 

您可以通过覆盖GetHashValue()Equals()为类解决这个问题。见here

3

您需要实现Equals()GetHashCode()Car类型。由于Car是引用类型,因此您可能会在字典中放置与该实例相同的Car(属性,但它们指向不同的对象)的差异实例,甚至不会意识到。

你不希望这是可能的

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"; 

GetHasCode(),你可以返回Id.GetHashCode()

Equals(),只是做了标准的样板检查,如检查,该类型是相同的,等。

This link提供有关为什么要实施GetHashCode()

+0

如果不为相同的车型创建重复的对象,这是不必要的。 – Scroog1 2013-02-26 16:48:20

+0

是的,但是如果你这样做,这是最好的做法和安全防范。你不想让它变得可能,这确保了。 – 2013-02-26 16:52:49

+0

我想我宁愿知道对象何时不是同一个实例。想象一下,你稍后会在Car类中添加一些可变状态;那么如果你以这种方式超越平等,你可能会遇到各种麻烦。或许更好的办法是让工厂在每次需要时为您提供您需要的特定Car实例。 – Scroog1 2013-02-27 09:19:05

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

添加到字典中更详细

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 

来获取值,你可以使用

var x=Cars[car1]; 

使用按键,其是不是在字典集合中会抛出一个好感主器件接收。

2

从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.

所以你的情况,你需要实现IEquatable<Car>,例如:

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; 
     } 
    } 
+0

你实际上并不需要实现'IEquatable',如果你愿意,你可以只覆盖'Equals'和'GetHashCode'。 – Servy 2013-02-26 16:45:04

+0

正确。我还发现,作为一个经验*的规则,如果要实现IEquatable 你仍然必须重写Object的equals和GetHashCode * http://blogs.msdn.com/b/jaredpar/archive/2009/01/15/if-you - 实施 - iequatable叔你,仍然必须修调对象S-等于-和gethashcode.aspx – sim1 2013-02-27 08:20:03