Controlla se esiste la chiave in NameValueCollection


141

Esiste un modo rapido e semplice per verificare se esiste una chiave in un NameValueCollection senza scorrere attraverso di essa?

Alla ricerca di qualcosa come Dictionary.ContainsKey () o simile.

Ci sono molti modi per risolverlo, ovviamente. Mi chiedo solo se qualcuno può aiutarmi a grattarmi il prurito al cervello.


basta usare Dizionario se si desidera effettuare una ricerca in base alla chiave .... A proposito: è possibile utilizzare l'indicizzatore in questa classe ma questo eseguirà il ciclo stesso - quindi nessun guadagno
Carsten

Risposte:


181

Da MSDN :

Questa proprietà restituisce null nei seguenti casi:

1) se la chiave specificata non viene trovata;

Quindi puoi semplicemente:

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

2) se viene trovata la chiave specificata e il valore associato è nullo.

collection[key]chiama base.Get()quindi base.FindEntry()che utilizza internamente Hashtablecon la prestazione O (1).


38
Questa proprietà restituisce null nei seguenti casi: 1) se la chiave specificata non viene trovata; e 2) se viene trovata la chiave specificata e il valore associato è nullo. Questa proprietà non distingue tra i due casi.
Steve,

1
@Andreas è per questo che è meglio archiviare una stringa vuota anziché nulla
abatishchev

@Steve OP non dice nulla su tale collisione.
abatishchev,

13
A destra @abatishchev, tuttavia l'OP dice "verifica se esiste una chiave". Prendere null come chiave non esiste non è vero. Alla fine non c'è risposta senza un compromesso (niente loop, usa stringhe vuote)
Steve

@abatishchev è come dire 0uguale a null... sry
Andreas Niedermair il

54

Usa questo metodo:

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

    return true;
}

È il più efficiente NameValueCollectione non dipende dal fatto che la raccolta contenga nullvalori o meno.


5
Ricorda using System.Linq;quando usi questa soluzione.
jhauberg,

14

Non credo che nessuna di queste risposte sia giusta / ottimale. NameValueCollection non solo non distingue tra valori null e valori mancanti, ma non distingue tra maiuscole e minuscole per quanto riguarda le chiavi. Quindi, penso che una soluzione completa sarebbe:

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

Mi piace questa soluzione. Guardando l'origine NameValueCollectionBase per impostazione predefinita utilizza InvariantCultureIgnoreCase, tuttavia ciò non significa che non ne sia passato uno diverso da utilizzare invece da qualunque classe crei un'istanza di NameValueCollection.
Lethek,

12

Sì, puoi usare Linq per controllare la AllKeysproprietà:

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

Tuttavia a Dictionary<string, string[]>sarebbe molto più adatto a questo scopo, forse creato tramite un metodo di estensione:

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
Ciò passerà in rassegna l'intera collezione che è O (n). Mentre collection[key]usa internamente Hashtableche è O (1)
abatishchev il

4
@abatishchev In effetti, tuttavia collection[key], non fa alcuna distinzione tra la chiave che non è presente e un valore null che viene archiviato rispetto a quella chiave.
Rich O'Kelly il

Inoltre puoi preformare un hack sporco e recuperare il campo privato di Hashtable usando Reflection.
abatishchev,

Penso che questa sia una soluzione piuttosto sciocca. Se qualcuno utilizza NameValueCollection è probabile che il dizionario non sia supportato, ad esempio avere una chiave null.
Chris Marisic,

0

È possibile utilizzare il Getmetodo e verificare nullche il metodo restituisca nullse NameValueCollection non contiene la chiave specificata.

Vedi MSDN .


È necessario conoscere indexil keyper chiamare il metodo. No?
abatishchev,

0

Se le dimensioni della raccolta sono ridotte, puoi scegliere la soluzione fornita da rich.okelly. Tuttavia, una grande raccolta significa che la generazione del dizionario potrebbe essere notevolmente più lenta della semplice ricerca della raccolta di chiavi.

Inoltre, se lo scenario di utilizzo è alla ricerca di chiavi in ​​diversi punti nel tempo, in cui NameValueCollection potrebbe essere stato modificato, la generazione del dizionario ogni volta potrebbe, di nuovo, essere più lenta della semplice ricerca della raccolta di chiavi.


0

Questa potrebbe anche essere una soluzione senza dover introdurre un nuovo metodo:

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

0

Come puoi vedere nelle fonti di riferimento, NameValueCollection eredita da NameObjectCollectionBase .

Quindi prendi il tipo base, ottieni l'hashtable privato tramite reflection e controlla se contiene una chiave specifica.

Affinché funzioni anche in Mono, devi vedere quale sia il nome dell'hashtable in mono, che è qualcosa che puoi vedere qui (m_ItemsContainer), e ottenere il campo mono, se il FieldInfo iniziale è null (mono- runtime).

Come questo

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

per il codice .NET 2.0 ultra-puro non riflettente, è possibile eseguire il ciclo delle chiavi, anziché utilizzare la tabella hash, ma è lento.

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

In VB è:

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

In C # dovrebbe essere solo:

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

Non sono sicuro se dovrebbe essere nullo ""ma questo dovrebbe aiutare.


Mi dispiace che sia in VB. C # dovrebbe essere solo if (MyNameValueCollection (Key)! = Null) {} Non sono sicuro che debba essere nullo o "", ma questo dovrebbe aiutare.
CodeShouldBeEasy,

Credo che la sintassi corretta sia simile a una Dictionarystruttura di dati, come in MyNameValueCollection[Key], piuttosto che MyNameValueCollection(Key), che prevede una chiamata di metodo.
Blairg23,

0

Sto usando questa raccolta, quando ho lavorato nella raccolta di piccoli elementi.

Dove molti elementi, penso che sia necessario utilizzare "Dizionario". Il mio codice:

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

O può essere usare questo:

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

0
queryItems.AllKeys.Contains(key)

Tenere presente che la chiave potrebbe non essere univoca e che il confronto è in genere sensibile al maiuscolo / minuscolo. Se vuoi semplicemente ottenere il valore della prima chiave corrispondente e non preoccuparti del caso, usa questo:

        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
   }

Valore restituito Tipo: System.Boolean true se NameValueCollection contiene chiavi che non sono null; altrimenti, falso. LINK


2
Mentre questo può rispondere alla domanda, alcune spiegazioni sono spesso apprezzate, in particolare per spiegare come questa possa essere una buona alternativa alle molte altre risposte.
Pac0

Questo controlla solo se la raccolta contiene delle chiavi. L'OP ha chiesto l'esistenza di una determinata chiave.
Bill Tür
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.