Periksa apakah kunci ada di NameValueCollection


141

Apakah ada cara cepat dan sederhana untuk memeriksa apakah ada kunci di NameValueCollection tanpa melalui itu?

Mencari sesuatu seperti Dictionary.ContainsKey () atau yang serupa.

Tentu saja ada banyak cara untuk menyelesaikannya. Hanya ingin tahu apakah seseorang dapat membantu menggaruk gatal otak saya.


cukup gunakan Kamus jika Anda ingin melakukan pencarian berdasarkan kunci .... BTW: Anda bisa menggunakan pengindeks pada kelas ini tetapi ini akan melakukan pengulangan sendiri - jadi tidak ada keuntungan
Carsten

Jawaban:


181

Dari MSDN :

Properti ini mengembalikan null dalam kasus berikut:

1) jika kunci yang ditentukan tidak ditemukan;

Jadi Anda bisa:

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

2) jika kunci yang ditentukan ditemukan dan nilai yang terkait adalah nol.

collection[key]panggilan base.Get()maka base.FindEntry()yang internal menggunakan Hashtabledengan kinerja O (1).


37
Properti ini mengembalikan null dalam kasus berikut: 1) jika kunci yang ditentukan tidak ditemukan; dan 2) jika kunci yang ditentukan ditemukan dan nilai yang terkait adalah nol. Properti ini tidak membedakan antara dua kasus.
Steve

1
@Andreas itu sebabnya lebih baik menyimpan string kosong daripada nol
abatishchev

@Steve OP tidak mengatakan apapun tentang tabrakan tersebut.
abatishchev

13
Benar @abatishchev, namun OP mengatakan 'memeriksa apakah ada kunci'. Mengambil null sebagai kunci tidak ada itu tidak benar. Pada akhirnya tidak ada jawaban tanpa kompromi (tidak ada putaran, gunakan string kosong)
Steve

@abatishchev itu seperti mengatakan 0sama dengan null... sry
Andreas Niedermair

54

Gunakan metode ini:

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

    return true;
}

Ini adalah yang paling efisien untuk NameValueCollectiondan tidak bergantung pada apakah koleksi mengandung nullnilai atau tidak.


5
Ingatlah using System.Linq;saat menggunakan solusi ini.
jhauberg

14

Saya tidak berpikir salah satu dari jawaban ini cukup benar / optimal. NameValueCollection tidak hanya tidak membedakan antara nilai nol dan nilai yang hilang, tetapi juga case-insensitive terkait dengan kunci itu. Jadi, saya pikir solusi lengkapnya adalah:

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

Saya suka solusi ini. Melihat sumber NameValueCollectionBase default untuk menggunakan InvariantCultureIgnoreCase, namun itu tidak berarti bahwa yang berbeda tidak diteruskan untuk digunakan sebagai gantinya oleh kelas apa pun yang membuat turunan dari NameValueCollection.
lethek

12

Ya, Anda dapat menggunakan Linq untuk memeriksa AllKeysproperti:

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

Namun a Dictionary<string, string[]>akan jauh lebih cocok untuk tujuan ini, mungkin dibuat melalui metode ekstensi:

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
Itu akan mengulang seluruh koleksi yang O (n). Sementara secara collection[key]internal menggunakan Hashtableyang O (1)
abatishchev

4
@abatishchev Memang, namun collection[key]tidak membuat perbedaan antara kunci tidak hadir dan nilai nol disimpan terhadap kunci itu.
Rich O'Kelly

Anda juga dapat membentuk sebelumnya hack kotor dan mengambil bidang pribadi Hashtable menggunakan Refleksi.
abatishchev

Saya pikir ini adalah solusi yang cukup konyol. Jika seseorang menggunakan NameValueCollection, kemungkinan karena alasan itu kamus tidak didukung, seperti memiliki kunci nol.
Chris Marisic

0

Anda bisa menggunakan Getmetode dan memeriksa nullsebagai metode akan kembali nulljika NameValueCollection tidak mengandung kunci yang ditentukan.

Lihat MSDN .


Anda perlu mengetahui indexcara keymemanggil metode. Bukan?
abatishchev

0

Jika ukuran koleksi kecil, Anda bisa menggunakan solusi yang disediakan oleh rich.okelly. Namun, koleksi besar berarti bahwa generasi kamus mungkin terasa lebih lambat daripada hanya mencari koleksi kunci.

Juga, jika skenario penggunaan Anda mencari kunci di berbagai titik waktu, di mana NameValueCollection mungkin telah dimodifikasi, membuat kamus setiap kali mungkin, lebih lambat, lebih lambat daripada hanya mencari koleksi kunci.


0

Ini juga bisa menjadi solusi tanpa harus memperkenalkan metode baru:

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

0

Seperti yang dapat Anda lihat di sumber referensi, NameValueCollection mewarisi dari NameObjectCollectionBase .

Jadi Anda mengambil tipe dasar, dapatkan hashtable pribadi melalui refleksi, dan periksa apakah itu berisi kunci tertentu.

Agar dapat bekerja di Mono juga, Anda perlu melihat apa nama hashtable di mono, yang merupakan sesuatu yang dapat Anda lihat di sini (m_ItemsContainer), dan dapatkan bidang-mono, jika FieldInfo awal adalah null (mono- runtime).

Seperti ini

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

untuk kode .NET 2.0 ultra-murni non-reflektif, Anda dapat mengulangi kunci, alih-alih menggunakan tabel hash, tapi itu lambat.

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

Di VB itu:

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

Dalam C # seharusnya:

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

Tidak yakin apakah harus nullatau ""tetapi ini akan membantu.


Maaf itu ada di VB. C # seharusnya jika (MyNameValueCollection (Key)! = Null) {} Tidak yakin apakah itu harus nol atau "" tetapi ini akan membantu.
CodeShouldBeEasy

Saya percaya sintaks yang benar mirip dengan Dictionarystruktur data, seperti pada MyNameValueCollection[Key], daripada MyNameValueCollection(Key), yang mengharapkan pemanggilan metode.
Blairg23

0

Saya menggunakan koleksi ini, ketika saya bekerja di koleksi elemen kecil.

Di mana banyak elemen, saya pikir perlu menggunakan "Kamus". Kode saya:

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

Atau dapat menggunakan ini:

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

0
queryItems.AllKeys.Contains(key)

Berhati-hatilah bahwa kunci mungkin tidak unik dan perbandingannya biasanya case-sensitive Jika Anda ingin mendapatkan nilai kunci pencocokan pertama dan tidak peduli tentang kasus, gunakan ini:

        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
   }

Return Value Type: System.Boolean true jika NameValueCollection berisi kunci yang bukan nol; jika tidak, salah. TAUTAN


2
Meskipun ini dapat menjawab pertanyaan, beberapa penjelasan sering dihargai, terutama untuk menjelaskan bagaimana ini bisa menjadi alternatif yang baik untuk banyak jawaban lainnya.
Pac0

Ini hanya memeriksa apakah koleksi berisi kunci sama sekali. OP meminta keberadaan kunci tertentu .
Bill Tür
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.