I have a ConcurrentDictionary:
private static ConcurrentDictionary<int, string> _cd = new ConcurrentDictionary<int, string>();
To be conservative, the actual key to be used to retrieve items is an object but I instead simply use its hash code as the key so that a (potentially large开发者_运维百科) object isn't the key:
public static string GetTheValue(Foo foo)
{
int keyCode = foo.GetHashCode(); // GetHashCode is overridden to guarantee uniqueness
string theValue = _cd.GetOrAdd(keyCode, FooFactory);
return theValue;
}
However, I need various properties in the Foo object when preparing an object in the Factory:
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;
}
Since the valueFactory parameter of GetOrAdd() expects Func<int, string>
, it appears that I cannot pass my Foo object to it. Is it at all possible to do so?
There is nothing wrong with using a large object as the key.
Unless the object is a struct
(and it should not be a struct), it will never be copied.
If you intend to be able to look things up later, your object will obviously stcik around, so you won't be leaking memory.
As long as you have reasonable (or inherited) GetHashCode()
and Equals()
implementations, there won't be any performance impact.
I think there is a fundamental misunderstanding here:
To be conservative, the actual key to be used to retrieve items is an object but I instead simply use its hash code as the key so that a (potentially large) object isn't the key.
I've bolded the phrases that I think you think are related. They're really not. If you're picturing your dictionary as being too large because its keys are these big objects, you're picturing it wrong. For reference types (any class
in C#), the keys will be stored in the dictionary only as references, which are the size of a whopping integer. And if you're concerned about passing the keys between methods, again: it's not what you think. Only references will be copied and passed around, not the objects themselves.
So I agree with SLaks: just use your Foo
type (or whatever it's really called) as the key in the first place. It will make your life a lot simpler.
I needed this for a different reason. If someone's else end up here like I did, here's how it can be done:
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;
}
精彩评论