web-dev-qa-db-fra.com

Vérifier si la clé existe dans NameValueCollection

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

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

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

126
Muhammad Yussuf

De MSDN :

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

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

Alors vous pouvez 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 null.

collection[key] appelle base.Get() puis base.FindEntry() qui utilise en interne Hashtable avec la performance O (1).

158
abatishchev

Utilisez cette méthode:

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

    return true;
}

C’est le plus efficace pour NameValueCollection et ne dépend pas de la collecte de noms ne contient ou non null valeurs.

48
Kirill Polishchuk

Je pense qu'aucune de ces réponses n'est tout à fait juste/optimale. NameValueCollection non seulement ne fait pas la distinction entre les valeurs null et les valeurs manquantes, il est également insensible à la casse en ce qui concerne les 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);
}
14
ChaseMedallion

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

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

Cependant, un Dictionary<string, string[]> serait bien plus adapté à cet usage, 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))
{
   ...
}
10
Rich O'Kelly

J'utilise cette collection lorsque j'ai travaillé dans une collection de petits éléments.

Là où beaucoup d'éléments, je pense besoin d'utiliser "Dictionnaire" . 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
Roberto Gata

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 dans la collection de clés. 

De même, si votre scénario d'utilisation recherche des clés à différents moments, lorsque NameValueCollection a peut-être été modifié, la génération du dictionnaire à chaque fois peut être encore plus lente que la simple recherche dans la collection de clés.

0
Jaguar

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

    item = collection["item"] != null ? collection["item"].ToString() : null;
0
codys-hole

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

Donc, vous prenez le type de base, obtenez la hashtable privée via 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 qui est quelque chose que vous pouvez voir ici (m_ItemsContainer), et obtenir le champ unique, si le FieldInfo initial null (mono-runtime).

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 un code .NET 2.0 ultra pur et non réfléchissant, vous pouvez effectuer une boucle sur les clés au lieu d'utiliser la table de hachage, mais cela 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
Stefan Steiger

Vous pouvez utiliser la méthode Get et rechercher null car celle-ci renverra null si NameValueCollection ne contient pas la clé spécifiée.

Voir MSDN .

0
Codrin Eugeniu
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 juste obtenir la valeur de la première clé correspondante sans 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;
        }
0
userSteve

Dans VB c'est:

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

En C # devrait juste être:

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

Vous ne savez pas si cela devrait être null ou "" mais cela devrait aider. 

0
CodeShouldBeEasy