如何根据具有相同哈希码的对象获取字典项?

How to get dictionary item based on an object with the same hashcode?

考虑以下私有成员:

private ConcurrentDictionary<CollectionInfo, ServiceInfo> _collectionsServicesMapping;

class CollectionInfo 覆盖并添加了一些额外的属性:

class CollectionInfo
{
    public Guid InstanceId { get; set; }

    public string CollectionName { get; set; }

    public string WorkFlowName { get; set; }

    public Guid DomainId { get; set; }

    public override bool Equals(object obj)
    {
        return obj is CollectionInfo && (obj as CollectionInfo).InstanceId.Equals(InstanceId);
    }

    public override int GetHashCode()
    {
        return InstanceId.GetHashCode();
    }
}

在我需要的上下文中,我正在通过 InstanceId 寻找 CollectionInfo

private IRequestHandler GetServiceByInstanceId(Guid instanceId)
{
}

我看到的两个可选方案:

_collectionsServicesMapping.TryGetValue(new CollectionInfo() { InstanceId = instanceId }, out si)

_collectionsServicesMapping.FirstOrDefault(x => x.Key.InstanceId.Equals(instanceId));

但这迫使我要么创建classCollectionInfo的冗余假实例,要么扫描所有字典.

有没有办法以另一种更有效的方式基于具有相同哈希码的对象来获取字典项?

我不认为你真的有问题。但是,让我们来看看它(请参阅最后我推荐的内容)。

Create a redundant fake instance

创建新实例是一项相对便宜的操作。当然,代码是否比直接使用 Guid 更难看。但如果这是你的顾虑,你有很多选择:

//excention method (in some static class)
public static ServiceInfo GetServiceByGuid (
   this ConcurrentDictionary<CollectionInfo, ServiceInfo> dic, Guid id){
   ServiceInfo si;
   dic.TryGetValue(new CollectionInfo() { InstanceId = id}, out si);
   return si;
}

//implicit coversion operator (in CollectionInfo)
public static implicit operator CollectionInfo(Guid id){
    return new CollectionInfo(new CollectionInfo() { InstanceId = id};
}

然后您可以将 Guid instanceId 传递给字典的 TryGetValue 方法。

Scan all the dictionary

没有理由采用这种方法。从技术上讲,您只是在扫描键而不是 "entire" 字典,但 TryGetValue 的性能会更高,因为它可以利用散列法快速找到您要查找的项目。

Change the dictionary

所以在那之后,这就是我认为你想要的:

ConcurrentDictionary<Guid, Tuple<CollectionInfo, ServiceInfo>>

这样你仍然可以获得并发,你可以根据一个guid(id)来匹配CollectionInfo/ServiceInfo,而且你不必搞乱重载(GetHashCode()CollectionInfo).

private IRequestHandler GetServiceByInstanceId(Guid instanceId)
{
   Tuple<CollectionInfo,ServiceInfo> pair;
   if (_collectionsServicesMapping.TryGetValue(instanceId, out pair))
   {
      return pair.Item2;
   }

   // whatever you want to return if instanceId wasn't found
   return null;
}

Is there a way to get a dictionary item, based on an object that has the same hashcode in another more efficient way?

很遗憾没有。与 Philip Pittle 的回答相反,我认为您(以及处于类似情况的任何其他人)do 有问题。我们是 过多封装 的受害者,从 Dictionary<TKey, TValue> 开始,然后是 ConcurentDictionary<TKey, TValue>。两个 classes 都可以很容易地公开像

这样的方法
IEnumerable<KeyValuePair<TKey, TValue>> GetItems(int hashCode) 

bool TryGetValue(int hashCode, Func<TKey, bool> predicate, out TValue value)

但他们没有。不幸的是,在 class 实现之外无法模拟类似的东西。

所以您被提到的变通办法困住了。我会选择 假实例 方法 - 至少你可以,有时没有这样的奢侈(如果 class 需要复杂的构造函数和强大的验证不允许假实例化)。并等待 MS 开源 BCL :-)

P.S。如果 Guid 创建一个不同的字典怎么样,如果它已经包含在 class 的实例中,为什么还要保留 Guid(16 字节值类型)的 2 个副本?