Vérifier si la clé existe dans NameValueCollection


141

Existe-t-il un moyen rapide et simple de vérifier si une clé existe dans un NameValueCollection sans la parcourir en boucle?

Vous recherchez quelque chose comme Dictionary.ContainsKey () ou similaire.

Il existe bien sûr de nombreuses façons de résoudre ce problème. Je me demandais juste si quelqu'un pouvait m'aider à me gratter le cerveau.


utilisez simplement Dictionary si vous voulez faire une recherche basée sur la clé .... BTW: vous pouvez utiliser l'indexeur sur cette classe mais cela fera la boucle elle-même - donc pas de gain
Carsten

Réponses:


181

Depuis MSDN :

Cette propriété renvoie null dans les cas suivants:

1) si la clé spécifiée n'est pas trouvée;

Vous pouvez donc simplement:

NameValueCollection collection = ...
string value = collection[key];
if (value == null) // key doesn't exist

2) si la clé spécifiée est trouvée et que sa valeur associée est nulle.

collection[key]appelle base.Get()alors base.FindEntry()qui utilise en interne Hashtableavec la performance O (1).


38
Cette propriété renvoie null dans les cas suivants: 1) si la clé spécifiée n'est pas trouvée; et 2) si la clé spécifiée est trouvée et que sa valeur associée est nulle. Cette propriété ne distingue pas les deux cas.
Steve

1
@Andreas c'est pourquoi il est préférable de stocker une chaîne vide au lieu de null
abatishchev

@Steve OP ne dit rien sur une telle collision.
abatishchev

13
À droite @abatishchev, cependant l'OP dit «vérifier si une clé existe». Prendre null comme clé n'existe pas n'est pas vrai. A la fin il n'y a pas de réponse sans compromis (pas de boucle, utilisez des chaînes vides)
Steve

@abatishchev c'est comme dire 0égal null... sry
Andreas Niedermair

54

Utilisez cette méthode:

private static bool ContainsKey(this NameValueCollection collection, string key)
{
    if (collection.Get(key) == null)
    {
        return collection.AllKeys.Contains(key);
    }

    return true;
}

C'est le plus efficace pour NameValueCollectionet ne dépend pas de si la collection contient des nullvaleurs ou non.


5
N'oubliez pas de le faire using System.Linq;lorsque vous utilisez cette solution.
jhauberg

14

Je ne pense pas qu'aucune de ces réponses soit tout à fait correcte / optimale. NameValueCollection ne fait pas seulement la distinction entre les valeurs nulles et les valeurs manquantes, il est également insensible à la casse en ce qui concerne ses clés. Ainsi, je pense qu'une solution complète serait:

public static bool ContainsKey(this NameValueCollection @this, string key)
{
    return @this.Get(key) != null 
        // I'm using Keys instead of AllKeys because AllKeys, being a mutable array,
        // can get out-of-sync if mutated (it weirdly re-syncs when you modify the collection).
        // I'm also not 100% sure that OrdinalIgnoreCase is the right comparer to use here.
        // The MSDN docs only say that the "default" case-insensitive comparer is used
        // but it could be current culture or invariant culture
        || @this.Keys.Cast<string>().Contains(key, StringComparer.OrdinalIgnoreCase);
}

J'aime cette solution. En regardant la source NameValueCollectionBase, elle utilise par défaut InvariantCultureIgnoreCase, mais cela ne signifie pas qu'une autre n'est pas transmise pour être utilisée à la place par n'importe quelle classe crée une instance de NameValueCollection.
lethek

12

Oui, vous pouvez utiliser Linq pour vérifier la AllKeyspropriété:

using System.Linq;
...
collection.AllKeys.Contains(key);

Cependant, un Dictionary<string, string[]>serait beaucoup plus adapté à cet objectif, peut-être créé via une méthode d'extension:

public static void Dictionary<string, string[]> ToDictionary(this NameValueCollection collection) 
{
    return collection.Cast<string>().ToDictionary(key => key, key => collection.GetValues(key));
}

var dictionary = collection.ToDictionary();
if (dictionary.ContainsKey(key))
{
   ...
}

1
Cela bouclera sur toute la collection qui est O (n). Bien qu'il collection[key]utilise en interne Hashtablece qui est O (1)
abatishchev

4
@abatishchev En effet, cependant, ne collection[key]fait aucune distinction entre la clé non présente et une valeur nulle stockée contre cette clé.
Rich O'Kelly

Vous pouvez également préformer un hack sale et récupérer le champ privé de Hashtable à l'aide de Reflection.
abatishchev

Je pense que c'est une solution assez idiote. Si quelqu'un utilise NameValueCollection, c'est probablement pour des raisons que le dictionnaire n'est pas pris en charge, comme avoir une clé nulle.
Chris Marisic

0

Vous pouvez utiliser la Getméthode et vérifier nullque la méthode retournera nullsi NameValueCollection ne contient pas la clé spécifiée.

Voir MSDN .


Vous devez connaître indexle keypour appeler la méthode. Pas toi?
abatishchev

0

Si la taille de la collection est petite, vous pouvez utiliser la solution fournie par rich.okelly. Cependant, une grande collection signifie que la génération du dictionnaire peut être sensiblement plus lente que la simple recherche de la collection de clés.

En outre, si votre scénario d'utilisation recherche des clés à différents moments dans le temps, où NameValueCollection a peut-être été modifié, la génération du dictionnaire à chaque fois peut, encore une fois, être plus lente que la simple recherche de la collection de clés.


0

Cela pourrait également être une solution sans avoir à introduire une nouvelle méthode:

    item = collection["item"] != null ? collection["item"].ToString() : null;

0

Comme vous pouvez le voir dans les sources de référence, NameValueCollection hérite de NameObjectCollectionBase .

Vous prenez donc le type de base, obtenez la table de hachage privée par réflexion et vérifiez si elle contient une clé spécifique.

Pour que cela fonctionne également en Mono, vous devez voir quel est le nom de la table de hachage en mono, ce que vous pouvez voir ici (m_ItemsContainer), et obtenir le champ mono, si le FieldInfo initial est nul (mono- Durée).

Comme ça

public static class ParameterExtensions
{

    private static System.Reflection.FieldInfo InitFieldInfo()
    {
        System.Type t = typeof(System.Collections.Specialized.NameObjectCollectionBase);
        System.Reflection.FieldInfo fi = t.GetField("_entriesTable", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

        if(fi == null) // Mono
            fi = t.GetField("m_ItemsContainer", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

        return fi;
    }

    private static System.Reflection.FieldInfo m_fi = InitFieldInfo();


    public static bool Contains(this System.Collections.Specialized.NameValueCollection nvc, string key)
    {
        //System.Collections.Specialized.NameValueCollection nvc = new System.Collections.Specialized.NameValueCollection();
        //nvc.Add("hello", "world");
        //nvc.Add("test", "case");

        // The Hashtable is case-INsensitive
        System.Collections.Hashtable ent = (System.Collections.Hashtable)m_fi.GetValue(nvc);
        return ent.ContainsKey(key);
    }
}

pour le code .NET 2.0 ultra-pur non réfléchissant, vous pouvez boucler sur les clés, au lieu d'utiliser la table de hachage, mais c'est lent.

private static bool ContainsKey(System.Collections.Specialized.NameValueCollection nvc, string key)
{
    foreach (string str in nvc.AllKeys)
    {
        if (System.StringComparer.InvariantCultureIgnoreCase.Equals(str, key))
            return true;
    }

    return false;
}

0

En VB c'est:

if not MyNameValueCollection(Key) is Nothing then
.......
end if

En C # devrait juste être:

if (MyNameValueCollection(Key) != null) { }

Je ne sais pas si cela devrait être nullou ""mais cela devrait aider.


Désolé, c'est dans VB. C # devrait juste être if (MyNameValueCollection (Key)! = Null) {} Je ne sais pas s'il doit être nul ou "" mais cela devrait aider.
CodeShouldBeEasy

Je crois que la syntaxe correcte est similaire à une Dictionarystructure de données, comme dans MyNameValueCollection[Key], plutôt que MyNameValueCollection(Key), qui attend un appel de méthode.
Blairg23

0

J'utilise cette collection, quand j'ai travaillé dans la collection de petits éléments.

Là où les éléments sont nombreux, je pense qu'il faut utiliser "Dictionary". Mon code:

NameValueCollection ProdIdes;
string prodId = _cfg.ProdIdes[key];
if (string.IsNullOrEmpty(prodId))
{
    ......
}

Ou peut être utiliser ceci:

 string prodId = _cfg.ProdIdes[key] !=null ? "found" : "not found";

0
queryItems.AllKeys.Contains(key)

Sachez que la clé peut ne pas être unique et que la comparaison est généralement sensible à la casse. Si vous voulez simplement obtenir la valeur de la première clé correspondante et ne pas vous soucier de la casse, utilisez ceci:

        public string GetQueryValue(string queryKey)
        {
            foreach (string key in QueryItems)
            {
                if(queryKey.Equals(key, StringComparison.OrdinalIgnoreCase))
                    return QueryItems.GetValues(key).First(); // There might be multiple keys of the same name, but just return the first match
            }
            return null;
        }

-1
NameValueCollection n = Request.QueryString;

if (n.HasKeys())
   {
       //something
   }

Type de valeur de retour: System.Boolean true si NameValueCollection contient des clés qui ne sont pas nulles; sinon, faux.LIEN


2
Bien que cela puisse répondre à la question, certaines explications sont souvent appréciées, notamment pour expliquer en quoi cela peut être une bonne alternative aux nombreuses autres réponses.
Pac0

Cela vérifie uniquement si la collection contient des clés. Le PO a demandé l'existence d'une certaine clé.
Bill Tür
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.