如何在不提供确切参考的情况下获得该值
本文关键字:情况下 参考 | 更新日期: 2023-09-27 18:20:48
更准确地说,我有这样的东西:
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中存在一个KeyValuePair,其MyState与kvp-MyAction具有完全相同,并且来自Dict的MyAction与kvp中的MyAction具有绝对相同的值)。唯一的区别是引用不同。
长话短说,有两个KeyValuePairs对象,它们都有相同的值(不同的引用),我如何从Dict中获得float value,而不必迭代整个字典来手动比较每个key.key和key.value,看看键是否真的相同:
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;
}
您需要确保在作为Dictionary键的MyState对象内部,您已经正确地重写了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)) {.....}
您需要在KeyValuePair<>
-类上实现GetHashCode()
和Equals()
。这些是Dictionary<>
用来查找密钥的方法。
规则是,如果覆盖Equals()
,则必须覆盖GetHashCode()
,因为必须确保两个"相等"的对象始终生成相同的哈希代码。这是Dictionary<>
正常工作所必需的。
Dictionary<>
首先通过搜索其哈希代码来寻找正确的密钥,然后才使用Equals()
来确保它真的找到了正确的密钥。
但是,对于不相等的对象,可以具有相同的哈希代码。例如,通过始终返回1
来实现GetHashCode()
是完全合法的,因为它满足相等对象具有相同哈希码的规则。然而,这会使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()
。
发布详细示例:
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
&GetHashCode
之后),它不允许你插入这些相同的键。