2011-02-10 1 views
1

J'ai un ConcurrentDictionary:ConcurrentDictionary.GetOrAdd(): valueFactory avec signature différente

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

Pour être prudent, la clé réelle à utiliser pour récupérer des éléments est un objet mais je plutôt utiliser simplement son code de hachage comme la clé de sorte qu'un objet (potentiellement important) n'est pas la clé:

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

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

    return theValue; 
} 

Cependant, j'ai besoin diverses propriétés dans l'objet Foo lors de la préparation d'un objet dans l'usine:

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

Étant donné que le paramètre valueFactory de GetOrAdd() s'attend à Func<int, string>, il semble que je ne puisse pas lui transmettre mon objet Foo. Est-il possible de le faire?

+2

Ne faites pas cela. Les HashCodes ne sont pas uniques. Vous devriez utiliser le grand objet; ça ne fera pas de mal. – SLaks

+0

@SLaks: Supposons que j'utilise ToString() au lieu de GetHashCode(). – Bullines

+1

** Ne le faites pas **. – SLaks

Répondre

2

Je pense qu'il ya un malentendu fondamental ici:

Pour être conservateur, la clé réelle à être utilisé pour récupérer des éléments est un objet mais je plutôt utiliser simplement son code de hachage comme touche afin qu'un objet (potentiellement ) ne soit pas la clé.

Je les ai phrases qui en caractères gras Je pense quevous penser sont liés. Ils ne sont vraiment pas. Si vous pensez que votre dictionnaire est trop grand parce que ses clés sont ces gros objets, vous vous trompez. Pour les types de référence (class en C#), les clés seront stockées dans le dictionnaire uniquement sous la forme références, qui sont la taille d'un nombre entier. Et si vous êtes préoccupé par le fait de passer les clés entre les méthodes, encore une fois: ce n'est pas ce que vous pensez. Seules les références seront copiées et transmises, pas les objets eux-mêmes.

Donc, je suis d'accord avec SLaks: il suffit d'utiliser votre type Foo (ou quel que soit son nom) comme la clé en premier lieu. Cela rendra votre vie beaucoup plus simple.

3

Il n'y a rien de mal à utiliser un objet volumineux comme clé.

À moins que l'objet ne soit un struct (et qu'il ne s'agisse pas d'une structure), il ne sera jamais copié.
Si vous avez l'intention de pouvoir regarder les choses plus tard, votre objet sera évidemment visible, donc vous ne ferez pas de fuite de mémoire.

Tant que vous avez des implémentations raisonnables (ou héritées) GetHashCode() et Equals(), il n'y aura aucun impact sur les performances.

+0

Juste par curiosité, dites-vous "il ne devrait pas être une structure" parce que le PO a précisé qu'il est grand?Ou êtes-vous en train de dire que les types de valeurs personnalisés ne devraient pas être utilisés comme des clés en général? Je devine le premier - je veux juste m'assurer. –

+0

@Dan: Correct. – SLaks

0

J'avais besoin de ceci pour une raison différente. Si quelqu'un d'autre finit ici comme je l'ai fait, voici comment cela peut être fait:

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