我需要一种为对象字典生成键的方法。但是,我有一些要求使这有点困难。这是场景:
private
,在静态类中。equal
到字典中的另一个对象,则密钥必须不同,因为它们是两个独立的对象。 解决方案#1
所有.Net对象都包含一个名为.GetHashCode()
的方法,该方法返回一个整数值。您可以将其用作密钥。
问题
不可能。 MSDN国家:
两个相等的对象返回相等的哈希码。
这打破了第5号请求,我假设(但没有测试)req。 #4。如果符合这些规则我会喜欢这样的选择。
解决方案#2
将指向对象的指针转换为int
并将其用作键。
问题
这打破了req的本质。 #3。传递指针并将它们用作键并不安全。
解决方案#3
将指向对象的指针转换为整数哈希值,并将哈希用作键。
问题
虽然这不违反任何规则,但我宁愿避免访问指针,因为这将涉及使用unsafe
代码。如果必须的话,我不反对使用不安全的代码,但如果可能的话,我宁愿避免使用它。
也许我的要求有点挑剔。必须有一些合理的方法从唯一对象派生密钥。有没有人经历过这种情况并解决了这个难题?
答案 0 :(得分:8)
1字典是ByRef对象的列表。
.NET中的对象总是“通过引用”。这可能是误解的开始。参考平等是您需要/想要的。
3外部代码需要获取字典中特定对象的密钥,但绝不能访问字典中的对象或字典本身。
这是真正的问题。没有它,对对象本身的引用就会起作用。但是框架仍然提供了所有功能,现成的:
private Dictionary<object, MyClass> _myStore;
// add an item and return a key
public object Add(MyClass item)
{
object key = new object();
_myStore.Add(key, item);
return key;
}
满足第4条要求:
private Dictionary<object, MyClass> _itemForKey; // was _myStore
private Dictionary<MyClass, object> _keyForItem;
// add an item and return a key
public object Add(MyClass item)
{
object key = new object();
_itemForKey.Add(key, item);
_keyForItem.Add(item, key);
return key;
}
protected object DeriveKeyFromItem(MyClass item)
{
return _keyForItem[item];
}
注意:这些示例不是线程安全的(请求6),但这是要解决的标准功能。
答案 1 :(得分:1)
我认为您的要求归结为您希望通过引用相等性进行比较和哈希。将此作为词典中的IEqualityComparer<T>
使用RuntimeHelpers.GetHashCode
和object.ReferenceEquals
即可。
public class ReferenceEqualityComparer<T> : IEqualityComparer<T>
{
public bool Equals(T x, T y)
{
return object.ReferenceEquals(x, y);
}
public int GetHashCode(T obj)
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
}
}
请注意,由于指针和引用aren't the same,您的引用不应该用作指针,从而降低了unsafe
代码使用不当的风险。
答案 2 :(得分:-1)
如何定义类似的结构:
public struct BlindIdentityToken : IEquatable<BlindIdentityToken>
{
Object o;
public BlindIdentityToken(Object obj)
{
o = obj;
}
public override int GetHashCode()
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(o);
}
public override bool Equals(object obj)
{
if (obj == null || obj.GetType() != typeof(BlindIdentityToken))
return false;
return ((BlindIdentityToken)obj).o == o;
}
public bool Equals(BlindIdentityToken other)
{
return o == other.o;
}
}
给定对象的引用,可以构造一个BlindIdentityToken
,它将与为同一个对象构造的任何其他BlindIdentityToken
进行比较,但会比较不等于其他任何东西。因为它是一种结构类型并实现IEquatable<BlindIdentityToken>
,所以构造一个令牌并在字典中查找它不需要堆分配。因为它使用RuntimeHelpers.GetHashCode()
,它应该忽略被封装引用的对象覆盖GetHashCode
的任何覆盖,并且因为o
是私有字段,所以它在某种程度上受到外部代码隐藏引用的保护它