如何在不给出确切参考的关键字的情况下获得该值?

时间:2015-11-05 17:36:04

标签: c# generics dictionary

更确切地说,我有这样的事情:

Dictionary<KeyValuePair<MyState, MyAction>, float> Dict = 
     new Dictionary<KeyValuePair<MyState, MyAction>, float>();

稍后,我有一个自定义的KeyValuePair对象;

KeyValuePair<MyState, MyAction> kvp = 
    new KeyValuePair<MyState, MyAction>(new MyState(...), new MyAction(...));

我的问题是:如果kvp状态和动作与Dict中的一对具有完全相同的值(在Dict中存在具有与kvp MyAction相同的MyState的KeyValuePair,并且来自Dict的MyAction具有完全相同的值, kvp中的MyAction)。唯一的区别是参考不同。

长话短说,有2个KeyValuePairs对象,两个都具有相同的值(不同的引用),如何从Dict获取浮点值,而不必迭代整个字典只是为了手动比较每个key.key和key。值只是为了看看密钥是否实际相同:

foreach(var StAct in Dict)
    if(StAct.Key.Key.Equals(kvp.Key) && 
        StAct.Key.Value.Equals(kvp.value))
  //where StAct.Key.Key is the MyState object and StAct.Key.Value is the MyAction object
    {
        MessageBox.Show(StAct.Value + "");
        break;
    }

3 个答案:

答案 0 :(得分:2)

您需要确保在MyState对象中作为Dictionary的键,您已正确覆盖了Equals()和GetHashCode()方法。

正如您所注意到的,类的默认行为是检查引用相等性,因此如果您想要某些不同的行为,则必须自己提供。

public class MyState
{
    public override bool Equals(object obj)
    {
        // your equality implementation goes here
    }

    public override int GetHashCode()
    {
        // your hashcode implementation goes here
    }
}

创建一个行为良好的GetHashCode()方法并不一定是微不足道的,但你可以在这个答案中找到一些关于如何做到这一点的好建议:https://stackoverflow.com/a/371348/5438433

完成后,您只需写下:

if(dict.ContainsKey(kvp.Key)) {.....}

答案 1 :(得分:0)

您需要在GetHashCode()级上实施Equals()KeyValuePair<>。这些是Dictionary<>用于查找密钥的方法。

规则是,如果覆盖GetHashCode(),则必须覆盖Equals(),因为必须确保两个“相等”对象始终生成相同的哈希码。这是Dictionary<>正常工作所必需的。

Dictionary<>首先通过搜索其哈希码来查找正确的密钥,然后才使用Equals()来确保它找到了正确的密钥。

但是,可以对于不相等的对象具有相同的哈希码。例如,通过始终返回GetHashCode()来实现1是完全合法的,因为它满足相等对象具有相同哈希码的规则。但是,它会使您的Dictionary<>操作非常慢 - 基本上,Dictionary<>现在必须搜索其所有条目才能找到正确的密钥,就像它是一个简单的列表一样。

您可能希望KeyValuePair<>的两个KeyValuePair<>对象是相同的,如果它们的键和它们的值依次相等。您可以这样实现:

public class KeyValuePair<K, V>
{
    private K m_key;
    private V m_value;

    // [...] existing implementation left out

    public override bool Equals(object obj)
    {
        KeyValuePair<K, V> other = obj as KeyValuePair<K, V>;
        if(other == null)
            return false;
        return object.Equals(this.m_key, other.m_key) && object.Equals(this.m_value, other.m_value);
    }

    public override int GetHashCode()
    {
        int hashCode = 0;
        if(m_key != null)
            hashCode += m_key.GetHashCode();
        if(m_value != null)
            hashCode = hashCode * 31 + m_value.GetHashCode();
        return hashCode;
    }
}

请注意,这要求K和V以对您有意义的方式实施Equals()GetHashCode()

答案 2 :(得分:0)

发布详细示例:

public class Foo
{
    public int Id { get; set; }
    public string  Name { get; set; }

    public override bool Equals(object obj)
    {   
        return this.Id==((Foo)obj).Id
            && this.Name==((Foo)obj).Name;
    }
    public override int GetHashCode()
    {
        return Id.GetHashCode() + Name.ToLower().GetHashCode();
    }
}

public class Bar
{
    public int SomeOtherId { get; set; }
    public string SomeOtherName { get; set; }

    public override bool Equals(object obj)
    {
        return this.SomeOtherId == ((Bar)obj).SomeOtherId
            && this.SomeOtherName == ((Bar)obj).SomeOtherName;
    }
    public override int GetHashCode()
    {
        return SomeOtherId.GetHashCode() + SomeOtherName.ToLower().GetHashCode();
    }
}

//Usage
var dict = new Dictionary<KeyValuePair<Foo, Bar>, float>();
dict.Add(new KeyValuePair<Foo, Bar>(new Foo { Id = 1, Name = "Foo" }, new Bar {SomeOtherId = 1, SomeOtherName = "Bar"}), 10);

Console.WriteLine(dict[new KeyValuePair<Foo, Bar>(new Foo { Id = 1, Name = "Foo" }, new Bar {SomeOtherId = 1, SomeOtherName = "Bar"})]);

答案是根据帖子的标题。但是,如果字典中有相同的键(尽管是不同的引用),它仍然不会跟随,因为当您尝试添加此类键时(在应用Equals&amp; GetHashCode之后),它不允许你插入这些相同的键。