ConcurrentDictionary.GetOrAdd():具有不同签名的valueFactory

时间:2011-02-10 15:24:43

标签: c# .net-4.0 concurrency

我有一个ConcurrentDictionary:

private static ConcurrentDictionary<int, string> _cd = new ConcurrentDictionary<int, string>();

保守一点,用于检索项目的实际密钥是一个对象,但我只是简单地使用其哈希代码作为密钥,以便(可能很大的)对象不是密钥:

public static string GetTheValue(Foo foo)
{
    int keyCode = foo.GetHashCode(); // GetHashCode is overridden to guarantee uniqueness

    string theValue = _cd.GetOrAdd(keyCode, FooFactory);

    return theValue;
}

但是,在Factory中准备对象时,我需要Foo对象中的各种属性:

private static string FooFactory(Foo foo)
{
    string result = null;

    object propA = foo.A;
    object propB = foo.B;

    // ... here be magic to set result

    return result;
}

由于GetOrAdd()的valueFactory参数需要Func<int, string>,因此我无法将Foo对象传递给它。是否有可能这样做?

3 个答案:

答案 0 :(得分:3)

使用大型对象作为密钥没有任何问题。

除非对象是struct(并且它不应该是结构),否则永远不会被复制。
如果你打算以后能够查看,那么你的对象显然会被破坏,所以你不会泄漏记忆。

只要您有合理(或继承)的GetHashCode()Equals()实施,就不会对性能产生任何影响。

答案 1 :(得分:2)

我认为这里有一个根本的误解:

  

保守,实际的关键   用于检索项目是一个对象   但我只是简单地使用它的哈希码   作为关键使a(可能   大)对象不是关键

我加粗了认为认为相关的短语。他们真的不是。如果你把你的字典想象得太大,因为它的键是这些大对象,你就会把它想象成错误。对于引用类型(C#中的任何class),键将仅作为引用存储在字典中,这是一个高达整数的大小。如果你担心在方法之间传递密钥,那么:这不是你的想法。只会复制和传递引用,而不是对象本身。

所以我同意SLaks:首先使用你的Foo类型(或其他任何名称)作为关键字。它会让你的生活变得更加简单。

答案 2 :(得分:0)

我出于不同的原因需要这个。如果有人的其他人像我一样在这里结束,那么就是这样做的:

public static string GetTheValue(Foo foo)
{
    int keyCode = ...

    string theValue = _cd.GetOrAdd(keyCode, (key => FooFactory(foo))); //key is not used in the factory

    return theValue;
}