【问题标题】:Dictionary<myField, myObject> where myField is a member of myObjectDictionary<myField, myObject> 其中 myField 是 myObject 的成员
【发布时间】:2012-07-28 07:32:45
【问题描述】:

是否可以在 C# 中创建一个由对象组成的字典,这样 Key 只是对字段值的引用(或者是 Value 的字段),所以它保证index == myDictionary[index].myField?

例如,想象一个标准的 C# Dictionary。假设我有Car 对象:

class Car {
    string name;
    int wheels;
    double weight;
    double horsepower;
    double topSpeed;

    // Appropriate constructors
}

我想存储在这个字典中,按名称索引:

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

var newCar = Car("Ford", 4, 2387.4, 4535.7, 128.2);
cars["Ford"] = newCar;

我的标准不能保证,因为我可以做到:

cars["Ford"].name = "not Ford";

而且条件被打破了。我可以简单地从Car 中删除name 字段,但是汽车本身不会知道它自己的名字——在这个时代,即使我们把性能成本放在一边,对于汽车来说这是一种尴尬的情况.

所以我的问题是:是否可以在 C# 中轻松制作哈希映射,使得哈希值始终等于哈希元素的某些部分,并且每当元素存在时更新哈希?

【问题讨论】:

  • hash is updated 如果您已经存储在哈希表中......您建议这应该如何工作?听起来字典可能不是您想要的结构。
  • 哈希对于任何对象都应该是不可变的。它必须基于定义对象身份的字段。在Equals(object) 方法中测试的相同。请勿更改哈希,否则将无法在字典中找到您的密钥。

标签: c# hash hashmap


【解决方案1】:

您正在描述KeyedCollection 类,但是如果在将项目添加到集合后更改它的键,则会遇到问题。

如果您想要一个哈希集合来处理对其标识属性的元素的更改,您可以在类型上实现 INotifyPropertyChanged(在您的示例中为Car),并让集合重新定位项目(或删除并重新添加它们) ) 如所须。这将是低效且极易出现错误的。

【讨论】:

  • 这是一个abstract 类。您能解释一下在这种情况下您将如何使用它吗?
  • @svick 通过从它派生一个具体类,与任何抽象类相同。
【解决方案2】:

您可以使用 C# 中的索引器http://msdn.microsoft.com/en-us/library/2549tw02.aspx 来实现它

【讨论】:

  • 索引器可能有用,但这不是这个问题的答案。您将如何使用索引器?
  • @svick 如果您查看链接中的 TempRecord 类示例。我在想是否可以用作字典
  • 请我解释一下-1
  • 就像我说的,这不是问题的答案。你提到的TempRecord 做了一些完全不同的事情。而普通的Dictionary 已经使用了索引器,你没有说索引器如何帮助解决这个问题。
【解决方案3】:

你可以考虑将类设计更改为:

class Car { public string name { get; private set; } }

因此,您将无法更改标识对象的部分。否则,字典似乎是一个不错的方法。

【讨论】:

    【解决方案4】:

    另一种方法是使用基于字符串的索引器构造您自己指定的CarDictionary,如下所示(假设Name 字段/属性为public):

    public class CarDictionary : List<Car>
    {
        public Car this[string name]
        {
            get { return this.Single(car => car.Name.Equals(name)); }
            set {
                var oldCar = this.SingleOrDefault(car => car.Name.Equals(name));
                if (oldCar != null) base.Remove(oldCar);
                value.Name = name;
                base.Add(value);
            }
        }
    
        public new void Add(Car car)
        {
            if (this.Any(c => c.Name.Equals(car.Name))) 
                throw new InvalidOperationException("Dictionary already contains a Car with the same name");
            base.Add(car);
        }
    }
    

    此外,您需要重新实现或隐藏其他基类方法,例如AddRangeRemove 等,以确保集合不会意外损坏。

    如果你现在初始化你的汽车“字典”并添加福特

    var cars = new CarDictionary();
    
    var newCar = new Car("Ford", 4, 2387.4, 4535.7, 128.2);
    cars["Ford"] = newCar;
    

    字典状态是:

    Number of cars: 1, name of first car: Ford
    

    如果你再尝试:

    cars["Ford"].Name = "not Ford";
    

    字典状态将是:

    Number of cars: 1, name of first car: not Ford
    

    接下来,使用重新实现的Add方法添加一个新的福特

    cars.Add(new Car("Ford", 6, 4000.0, 500.0, 100.0));
    

    将产生以下字典状态:

    Number of cars: 2, name of last car: Ford
    

    尝试使用Add 方法添加另一个Ford 将产生异常:

    var anotherFord = new Car("Ford", 3, 1000.0, 50.0, 120.0);
    cars.Add(anotherFord);
    
    InvalidOperationException: Dictionary already contains a Car with the same name
    

    但如果你改用索引器,新的福特将取代旧的:

    cars["Ford"] = anotherFord;
    
    Number of cars: 2, name of last car: Ford
    

    最后,使用索引器向字典添加新的Car 的一个特点是索引器可能(应该?)更改添加的Car 的名称:

    cars["thought this was a Ford?"] = anotherFord;
    
    Number of cars: 3, name of last car: thought this was a Ford?
    

    据我所知,这将是索引器设置器的预期行为。如果不希望出现这种行为,只需删除该行

    value.Name = name;
    

    来自索引器设置器实现。

    【讨论】:

      猜你喜欢
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-08
      • 2021-08-06
      • 1970-01-01
      • 1970-01-01
      • 2019-11-05
      相关资源
      最近更新 更多