我的哈希表值是否应包含密钥

时间:2012-12-06 18:58:45

标签: c# hashtable

我正在就这个来回辩论。我想要一个Hashtable(或字典......两者似乎都为此目的做得好)

我有一个具有ItemNumber,Description和Quantity的类Item。我有一个ItemCollection类(当前使用Item数组),我想使用哈希表或字典。在我的Item类中,我使用ItemNumber来比较项a == item b。

所以我应该将ItemNumber移动到ItemCollection作为我的哈希表的键,或者我应该离开它。部分我想离开它,因为我根据Item生成了一个表。但是我的另一部分认为这是多余和愚蠢的。

我的最终目标是通过执行类似的操作来查看作为发货项目的ItemCollection是否等于另一个ItemCollection(订单)。

foreach(var package in shipments)
    foreach(var item in package)
       shipOrder += item;

return mainOrder==shipOrder;

我希望这是有道理的。我的头仍然有点生病,所以我需要澄清一些,请告诉我。

修改

好的,所以我想到了每个人都说了什么,并尝试过,大多数测试都通过了,除了一个,我无法弄清楚为什么。所以我会发布我所拥有的内容,看看你们是否可以找出我的愚蠢错误。

public class Item
{
    public Item(object[] array)
    {
        ItemNumber = array[0].ToString();
        Description = array[1].ToString();
        Quantity = (int)array[2];
    }
    public Item(string item, string desc, int qty)
    {
        ItemNumber = item;
        Description = desc;
        Quantity = qty;
    }
    /// <summary>
    /// </summary>
    public string ItemNumber;
    public string Description;
    public int Quantity;

    public override bool Equals(object obj)
    {
        //return compareTwoItems(this, (Item)obj);
        return this.GetHashCode() == obj.GetHashCode();
    }
    public static bool operator ==(Item ic1, Item ic2)
    {
        return compareTwoItems(ic1, ic2);
    }
    public static bool operator !=(Item ic1, Item ic2)
    {
        return !compareTwoItems(ic1, ic2);
    }
    private static bool compareTwoItems(Item ic1, Item ic2)
    {
        return (ic1.ItemNumber == ic2.ItemNumber)
            && (ic1.Quantity == ic2.Quantity);
    }
    public override int GetHashCode()
    {
        return ItemNumber.GetHashCode() ^ Quantity;
    }
}
public class ItemCollection : System.Collections.Generic.SortedDictionary<string, Item>
{
    public ItemCollection()
    {
    }
    public void AddItem(Item i)
    {
        this.Add(i.ItemNumber, i);
    }

    public string TrackNumber = "";
    /// <summary>
    /// Check to see if the Two ItemCollections have the same Quantity of items. If not it may be that the order was not completed
    /// </summary>
    /// <param name="obj">the sales order items</param>
    /// <returns>True if the quantity of the two collections are the same.</returns>
    /// <exception cref="ArgumentException">If the collections have different counts, or if ItemNumbers differ in one of the elements</exception>
    public override bool Equals(object obj)
    {
        return this.GetHashCode() == ((ItemCollection)obj).GetHashCode();
    }
    public override int GetHashCode()
    {
        int hash = 0;
        foreach (var item in this.Values)
            hash ^= item.GetHashCode();

        return hash;
    }
    /// <summary>
    /// Check to see if the Two ItemCollections have the same Quantity of items. If not it may be that the order was not completed
    /// </summary>
    /// <param name="ic1">the sales order items</param>
    /// <param name="ic2">the shipping ticket items</param>
    /// <returns>True if the quantity of the two collections are the same.</returns>
    /// <exception cref="ArgumentException">If the collections have different counts, or if ItemNumbers differ in one of the elements</exception>
    public static bool operator ==(ItemCollection ic1, ItemCollection ic2)
    {
        return ic1.Equals(ic2);
    }
    public static bool operator !=(ItemCollection ic1, ItemCollection ic2)
    {
        return !ic1.Equals(ic2);
    }
}

单元测试

    [TestMethod, TestCategory("ItemColl")]
    public void ItemCollectionPassTest()
    {
        MSSqlDatabase db = new MSSqlDatabase();
        ItemCollection salesOrder = db.GetItemsCollectionFromSalesOrder(4231);
        ItemCollection items = db.GetItemsCollectionFromSalesOrder(4231);

        Assert.AreEqual(salesOrder, items); //passes
        Assert.IsTrue(salesOrder == items); //passes
    }
    [TestMethod, TestCategory("ItemColl")]
    public void ItemCollectionDifferentQuantity()
    {
        MSSqlDatabase db = new MSSqlDatabase();
        ItemCollection salesOrder1 = db.GetItemsCollectionFromSalesOrder(4231);
        ItemCollection salesOrder2 = db.GetItemsCollectionFromSalesOrder(4232);
        Assert.AreNotEqual(salesOrder1, salesOrder2); //passes
        Assert.IsTrue(salesOrder1 != salesOrder2); //passes

        ItemCollection[] items = db.GetItemsCollectionFromShipping(4231);
        ItemCollection test = items[0];
        Assert.AreNotEqual(salesOrder1, test); //Fails
        CollectionAssert.AreNotEqual(salesOrder1, items[0]); // passes
    }

....现在由于某种原因它可以工作......我在我的代码中改变了一件物品中的GetHash方法(忘了用ItemNumber中的哈希来计算数量)现在他们通过......奇怪的。但我会发布我的代码,因为它可能有助于某人。

2 个答案:

答案 0 :(得分:1)

我同意scarle88,我认为您的ItemCollection应该延伸DictionaryHashtable。字典对于每个项目都需要一个唯一的密钥,您可以使用该项目编号(如果您的要求是每个项目都是唯一的)。

像这样:

public class Item {
    public string ItemNumber { get; set; }
    public string Description { get; set; }
    public string Quantity { get; set; }

    public override bool Equals(Object o) {
        // Implement your Equals here
    }
    public override int GetHashCode() {
        // Implement your hash code method here
    }
}

public class ItemCollection : Dictionary<string, Item> {
    public override bool Equals(Object o) {
        // Implement your collection's Equals method here
    }
}

我不确定您对比较收藏品的要求是什么。但是如果你只关心两个集合都有相同的项目,你可以像这样实现ItemCollection.Equals

public override bool Equals(Object o) {
    if (o == null)
        return false;
    if (!(o is ItemCollection))
        return false;
    var other = o as ItemCollection;

    // check the 'this' collection
    foreach (var item in this.Keys) {
        if (item != null && !other.ContainsKey(item.ItemNumber))
            return false;

    // check the 'other' collection
    foreach (var item in other.Keys) {
        if (item != null && !this.ContainsKey(item.ItemNumber))
            return false;
    return true;
}

答案 1 :(得分:0)

您可以使用HashTable<T>作为集合,并在Item类中覆盖基础对象Equals()GetHashCode()方法。

Why is it important to override GetHashCode when Equals method is overridden?