web-dev-qa-db-fra.com

Impossible d'ajouter keyValuePair directement au dictionnaire

Je voulais ajouter un KeyValuePair<T,U> À un Dictionary<T, U> Et je n'ai pas pu. Je dois passer la clé et la valeur séparément, ce qui signifie que la méthode Add doit créer un nouvel objet KeyValuePair à insérer, ce qui ne peut pas être très efficace. Je ne peux pas croire qu'il n'y ait pas de surcharge Add(KeyValuePair<T, U>) sur la méthode Add. Quelqu'un peut-il suggérer une raison possible de cette omission apparente?

30
Dave

Sauvegardez une minute ... avant de vous lancer dans la surveillance, vous devez déterminer si la création d'un nouveau KeyValuePair est vraiment si inefficace.

Tout d'abord, la classe Dictionary n'est pas implémentée en interne comme un ensemble de paires clé/valeur, mais comme un groupe de tableaux. Cela mis à part, supposons qu'il ne s'agissait que d'un ensemble de paires de valeurs clés et examinons l'efficacité.

La première chose à noter est que KeyValuePair est une structure. La véritable implication de cela est qu'il doit être copié de la pile vers le tas afin d'être passé en tant que paramètre de méthode. Lorsque le KeyValuePair est ajouté au dictionnaire, il devrait être copié une deuxième fois pour garantir la sémantique du type de valeur.

Afin de passer la clé et la valeur en tant que paramètres, chaque paramètre peut être soit un type de valeur, soit un type de référence. S'il s'agit de types de valeur, les performances seront très similaires à celles de l'itinéraire KeyValuePair. S'il s'agit de types de référence, cela peut en fait être une implémentation plus rapide car seule l'adresse doit être contournée et très peu de copie doit être effectuée. Dans le meilleur et le pire des cas, cette option est légèrement meilleure que l'option KeyValuePair en raison de l'augmentation des frais généraux de la structure KeyValuePair elle-même.

32
Tim Copenhaver

Vous pouvez utiliser l'interface IDictionary<TKey,TValue> Qui fournit la méthode Add(KeyValuePair<TKey,TValue>):

IDictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(new KeyValuePair<int,string>(0,"0"));
dictionary.Add(new KeyValuePair<int,string>(1,"1"));
32
DmitryG

Il existe une telle méthode - ICollection<KeyValuePair<K, T>>.Add mais tel qu'il est explicitement implémenté, vous devez convertir votre objet dictionnaire sur cette interface pour y accéder.

((ICollection<KeyValuePair<KeyType, ValueType>>)myDict).Add(myPair);

Voir

Le page de cette méthode comprend un exemple.

14
Richard

Sauf erreur, .NET 4.5 et 4.6 ajoute la possibilité d'ajouter un KeyValuePair à un dictionnaire. (Si je me trompe, informez-moi et je supprimerai cette réponse.)

https://msdn.Microsoft.com/en-us/library/cc673027%28v=vs.110%29.aspx

À partir du lien ci-dessus, l'information pertinente est cet exemple de code:

public static void Main() 
{
    // Create a new dictionary of strings, with string keys, and 
    // access it through the generic ICollection interface. The 
    // generic ICollection interface views the dictionary as a 
    // collection of KeyValuePair objects with the same type 
    // arguments as the dictionary. 
    //
    ICollection<KeyValuePair<String, String>> openWith =
        new Dictionary<String, String>();

    // Add some elements to the dictionary. When elements are  
    // added through the ICollection<T> interface, the keys 
    // and values must be wrapped in KeyValuePair objects. 
    //
    openWith.Add(new KeyValuePair<String,String>("txt", "notepad.exe"));
    openWith.Add(new KeyValuePair<String,String>("bmp", "Paint.exe"));
    openWith.Add(new KeyValuePair<String,String>("dib", "Paint.exe"));
    openWith.Add(new KeyValuePair<String,String>("rtf", "wordpad.exe"));

    ...
}

Comme on peut le voir, un nouvel objet de type Dictionary est créé et appelé openWith. Un nouvel objet KVP est ensuite créé et ajouté à openWith à l'aide de .Add méthode.

2
Machtyn

Si quelqu'un veut vraiment le faire, voici une extension

    public static void Add<T, U>(this IDictionary<T, U> dic, KeyValuePair<T, U> KVP)
    {
        dic.Add(KVP.Key, KVP.Value);
    }

mais je recommanderais de ne pas le faire s'il n'y a pas vraiment besoin de le faire

2
WiiMaxx

ce n'est pas parce que l'énumérateur de la classe Dictionary renvoie un KeyValuePair que c'est ainsi qu'il est implémenté en interne.

utilisez IDictionary si vous avez vraiment besoin de passer des KVP parce que vous les avez déjà dans ce format. sinon, utilisez l'affectation ou utilisez simplement la méthode Add.

1
Mike Corcoran

Quel serait le problème avec simplement l'ajout dans votre projet en tant qu'extension?

namespace System.Collection.Generic
{
    public static class DictionaryExtensions
    {
        public static void AddKeyValuePair<K,V>(this IDictionary<K, V> me, KeyValuePair<K, V> other)
        {
            me.Add(other.Key, other.Value);
        }
    }
}
0
Machtyn