2011-02-10 4 views
1

У меня есть ConcurrentDictionary:ConcurrentDictionary.GetOrAdd(): valueFactory с другой сигнатурой

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

Однако, мне нужны различные свойства объекта 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; 
} 

Поскольку параметр valueFactory GetOrAdd() ожидает Func<int, string>, похоже, что я не могу передать свой объект Foo. Неужели это возможно?

+2

Не делайте этого. HashCodes не уникальны. Вы должны использовать большой объект; это не повредит. – SLaks

+0

@SLaks: Предположим, я использую ToString() вместо GetHashCode(). – Bullines

+1

** Просто не **. – SLaks

ответ

2

Я думаю, что есть фундаментальное непонимание здесь:

Чтобы быть консервативным, фактический ключ к использоваться для извлечения элементов является объектом , но вместо этого я просто использовать его хэш-код как ключ , так что объект (потенциально большой) не является ключом.

Я жирный шрифт фразы, которые я думать вы думает, связаны. Они на самом деле нет. Если вы представляете свой словарь слишком большим, потому что его ключи - это большие объекты, вы представляете, что это неправильно. Для ссылочных типов (любые class в C#) ключи будут храниться в словаре только как ссылки, размер которых является целым числом. И если вы беспокоитесь о передаче ключей между методами, еще раз: это не то, что вы думаете. Только ссылки будут скопированы и переданы, а не сами объекты.

Итак, я согласен с SLaks: просто используйте свой тип Foo (или что-то еще, что он действительно называется) в качестве ключа в первую очередь. Это сделает вашу жизнь намного проще.

3

Нет ничего плохого в использовании большого объекта в качестве ключа.

Если объект не является struct (и он не должен быть структурой), он никогда не будет скопирован.
Если вы собираетесь иметь возможность смотреть вещи позже, ваш объект будет явно stcik, поэтому вы не будете пропускать память.

До тех пор, пока у вас есть разумные (или унаследованные) GetHashCode() и Equals() реализаций, никакого воздействия на производительность не будет.

+0

Просто из любопытства вы говорите: «Это не должна быть структура», потому что ОП указал, что он большой?Или вы говорите, что пользовательские типы значений не должны использоваться в качестве ключей вообще? Я предполагаю, что первый - просто хочу убедиться. –

+0

@ Dan: Правильно. – SLaks

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; 
} 
Смежные вопросы