如何基于具有相同哈希码的对象获取字典项

本文关键字:对象 获取 字典 哈希码 何基于 | 更新日期: 2023-09-27 18:13:42

考虑以下私有成员:

private ConcurrentDictionary<CollectionInfo, ServiceInfo> _collectionsServicesMapping;

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));

但是这迫使我要么创建一个多余的假实例 CollectionInfo类,要么扫描所有的字典

是否有一种方法来获得一个字典项,基于一个对象,具有相同的哈希码在另一个更有效的方式?

如何基于具有相同哈希码的对象获取字典项

是否有一种方法来获得一个字典项,基于一个对象,具有相同的哈希码在另一个更有效的方法?

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

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

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

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

因此,您只能使用前面提到的解决方法。我将选择伪实例方法—至少您可以,有时没有这样的奢侈(如果类需要具有强验证的复杂构造函数,不允许伪实例化)。然后等待微软开源BCL:-)

注:如何通过Guid创建不同的字典,为什么要保留Guid(16字节值类型)的2个副本,如果它已经包含在一个类的实例中?

我不认为你真的有问题。但是让我们从头到尾看一遍(看我推荐的内容)。

创建一个冗余的假实例

创建一个新实例是一个相对便宜的操作。代码是不是比直接使用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方法。

扫描所有的字典

没有理由采取这种方法。从技术上讲,你只扫描键,而不是"整个"字典,但TryGetValue将更高效,因为它可以利用哈希来快速找到你正在寻找的项目。

更改字典

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

ConcurrentDictionary<Guid, Tuple<CollectionInfo, ServiceInfo>>

这样你仍然可以获得并发性,你可以基于guid (id)匹配CollectionInfo/ServiceInfo,并且你不必与超载(CollectionInfo中的GetHashCode())混淆。

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;
}