使用Object作为Dictionary键

时间:2011-03-25 09:54:14

标签: .net

我想将以下对象用作Dictionary键。如果类别目标相等,则密钥相等。任何解决方案?

public class TargetKey
{
    public TargetKey(Categories category_arg, String target_arg)
    {
        catetory = category_arg;
        target = target_arg;
    }
    private Categories catetory;
    public Categories Catetory
    {
        get { return catetory; }
        //set { catetory = value; }
    }
    private String target;
    public String Target
    {
        get { return target; }
        //set { target = value; }
    }
}

不良解决方案

首先调用GetHashCode(),如果散列等于,则调用Equals()。 所以我添加了以下两种方法:

    public override bool Equals(object obj)
    {
        TargetKey other = obj as TargetKey;
        return other.Catetory == this.Catetory && other.Target == this.Target;
    }

    public override int GetHashCode()
    {
        return 0;  //this will leads to ONLY 1 bucket, which defeat the idea of Dictionary.
    }

精制溶液

    public override bool Equals(object obj)
    {
        TargetKey other = obj as TargetKey;
        return other.Catetory == this.Catetory && other.Target == this.Target;
    }

    public override int GetHashCode()
    {
        Int32 hash = this.Target.GetHashCode() + this.Catetory.GetHashCode(); 
        // This will introduce some more buckets. Though may not be as many as possible.
        return hash;
    }

4 个答案:

答案 0 :(得分:4)

根据您的类别和目标覆盖并实施Equals()GetHashCode(),这样就可以将它们用作比较作为字典的关键字。

这是一个建议的实现,但究竟需要做什么将取决于它们是否为null。我假设它们可以在下面的实现中,因为构造函数中没有空检查:

public class TargetKey
{
    public TargetKey(Categories category_arg, String target_arg)
    {
        Catetory = category_arg;
        Target = target_arg;
    }
    private Categories catetory;
    public Categories Catetory
    {
        get { return catetory; }
    }
    private String target;
    public String Target
    {
        get { return target; }
    }

    public bool Equals (TargetKey other)
        {
        if (ReferenceEquals (null, other))
            {
            return false;
            }
        if (ReferenceEquals (this, other))
            {
            return true;
            }
        return Equals (other.catetory, catetory) && Equals (other.target, target);
        }

    public override bool Equals (object obj)
        {
        if (ReferenceEquals (null, obj))
            {
            return false;
            }
        if (ReferenceEquals (this, obj))
            {
            return true;
            }
        if (obj.GetType () != typeof (TargetKey))
            {
            return false;
            }
        return Equals ((TargetKey) obj);
        }

    public override int GetHashCode ()
        {
        unchecked
            {
            return ((catetory != null ? catetory.GetHashCode () : 0)*397) ^ (target != null ? target.GetHashCode () : 0);
            }
        }
}

答案 1 :(得分:1)

您可以覆盖GetHashCodeEquals

Dictionary使用这两种方法来确定两个键是否相等。这也是它查找键值的方式。请参阅GetHashCode文档,了解Dictionary如何执行此操作。

[编辑]
查看哈希码的(非常)原始方法是作为大数组的索引。

bool ContainsKey(object key)
{
    int hashCode = key.GetHashCode();
    object foundKey = this.keys[hashCode];
    return key.Equals(foundKey);
}

请注意,这是一种非常简化的字典实现方式。真正的字典不会有庞大的数组。真正的字典会进行空检查。真正的字典可以使用相同的哈希代码处理不同的密钥,尽管密钥类型会影响性能。等

答案 2 :(得分:0)

如果密钥是类的一部分,则使用KeyedCollection。 它是一个字典,其中键是从对象派生的。 在封面下它是字典。不必重复键和值中的键。 为什么键中的键与值不一样。不必在内存中复制相同的信息。

您没有定义类别或类别,因此使用了字符串。

KeyedCollection类

公开复合键的索引器

using System.Collections.ObjectModel;

namespace KeyCollStringString
{
    class Program
    {
        static void Main(string[] args)
        {
            StringStringO ss1 = new StringStringO("Sall","John");
            StringStringO ss2 = new StringStringO("Sall", "John");
            if (ss1 == ss2) Console.WriteLine("same");
            if (ss1.Equals(ss2)) Console.WriteLine("equals");
            // that are equal but not the same I don't override = so I have both features

            StringStringCollection stringStringCollection = new StringStringCollection();
            // dont't have to repeat the key like Dictionary
            stringStringCollection.Add(new StringStringO("Ringo", "Paul"));
            stringStringCollection.Add(new StringStringO("Mary", "Paul"));
            stringStringCollection.Add(ss1);
            //this would thow a duplicate key error
            //stringStringCollection.Add(ss2);
            //this would thow a duplicate key error
            //stringStringCollection.Add(new StringStringO("Ringo", "Paul"));
            Console.WriteLine("count");
            Console.WriteLine(stringStringCollection.Count.ToString());
            // reference by ordinal postion (note the is not the long key)
            Console.WriteLine("oridinal");
            Console.WriteLine(stringStringCollection[0].GetHashCode().ToString());
            // reference by index
            Console.WriteLine("index");
            Console.WriteLine(stringStringCollection["Mary", "Paul"].GetHashCode().ToString());
            Console.WriteLine("foreach");
            foreach (StringStringO ssO in stringStringCollection)
            {
                Console.WriteLine(string.Format("HashCode {0} String1 {1} String2 {2} ", ssO.GetHashCode(), ssO.String1, ssO.String2));
            }
            Console.WriteLine("sorted by date");
            foreach (StringStringO ssO in stringStringCollection.OrderBy(x => x.String1).ThenBy(x => x.String2))
            {
                Console.WriteLine(string.Format("HashCode {0} String1 {1} String2 {2} ", ssO.GetHashCode(), ssO.String1, ssO.String2));
            }
            Console.ReadLine();
        }
        public class StringStringCollection : KeyedCollection<StringStringS, StringStringO>
        {
            // This parameterless constructor calls the base class constructor 
            // that specifies a dictionary threshold of 0, so that the internal 
            // dictionary is created as soon as an item is added to the  
            // collection. 
            // 
            public StringStringCollection() : base(null, 0) { }

            // This is the only method that absolutely must be overridden, 
            // because without it the KeyedCollection cannot extract the 
            // keys from the items.  
            // 
            protected override StringStringS GetKeyForItem(StringStringO item)
            {
                // In this example, the key is the part number. 
                return item.StringStringS;
            }

            //  indexer 
            public StringStringO this[string String1, string String2]
            {
                get { return this[new StringStringS(String1, String2)]; }
            }
        }

        public struct StringStringS
        {   // required as KeyCollection Key must be a single item
            // but you don't reaaly need to interact with Int32Int32s
            public readonly String String1, String2;
            public StringStringS(string string1, string string2) { this.String1 = string1.Trim(); this.String2 = string2.Trim(); }
        }
        public class StringStringO : Object
        {
            // implement you properties
            public StringStringS StringStringS { get; private set; }
            public String String1 { get { return StringStringS.String1; } }
            public String String2 { get { return StringStringS.String2; } }
            public override bool Equals(Object obj)
            {
                //Check for null and compare run-time types.
                if (obj == null || !(obj is StringStringO)) return false;
                StringStringO item = (StringStringO)obj;
                return (this.String1 == item.String1 && this.String2 == item.String2);
            }
            public override int GetHashCode() 
            {
                int hash = 17;
                // Suitable nullity checks etc, of course :)
                hash = hash * 23 + String1.GetHashCode();
                hash = hash * 23 + String1.GetHashCode();
                return hash;
            }
            public StringStringO(string string1, string string2)
            {
                StringStringS stringStringS = new StringStringS(string1, string2);
                this.StringStringS = stringStringS;
            }
        }
    }
}

答案 3 :(得分:-1)

只需使用通用字典集(C#代码)

Dictionary<TargetKey> objMyCollection = new Dictionary<TargetKey>.();

使用objMyCollection的ContainsKey()方法,如:

if(objMyCollection.ContainsKey(new TargetKey()) 
{
    MessageBox.Show("Obj find");
}
else
{
    MessageBox.Show("key not found add new one");
}