3

是否可以在 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";

并且条件被打破。我可以简单地name从 中删除该字段Car,但是汽车本身将不知道自己的名字——即使我们抛开性能成本,在当今时代,汽车处于一种尴尬的境地。

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

4

4 回答 4

2

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

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

于 2012-07-30T15:55:29.817 回答
0

一种替代方法是使用基于字符串的索引器构建您自己的指定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以确保集合不会意外损坏。

如果您现在初始化您的汽车“字典”并添加Ford

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方法添加一个新的Ford

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

将产生以下字典状态:

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

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

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;

从索引器设置器实现。

于 2012-07-31T07:14:51.647 回答
0

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

于 2012-07-30T15:41:39.247 回答
0

您可以考虑将课程设计更改为:

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

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

于 2012-07-30T15:51:16.343 回答