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

时间:2015-09-21 16:08:18

标签: c# dictionary hashcode

考虑以下私人成员:

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的冗余假实例扫描所有字典

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

2 个答案:

答案 0 :(得分:1)

我认为你真的没有问题。但是让我们来看看(看看我推荐的结果)。

  

创建冗余假实例

创建新实例是一种相对便宜的操作。代码有点丑陋然后直接使用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,并且你不必混淆重载(GetHashCode() { {1}})。

CollectionInfo

答案 1 :(得分:1)

  

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

不幸的是没有。与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)

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

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

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