Перевірте, чи існує ключовий ключ у NameValueCollection


141

Чи існує швидкий і простий спосіб перевірити, чи існує ключ у NameValueCollection, не перебираючи його?

Шукаєте щось на кшталт Dictionary.ContainsKey () або подібне.

Звичайно, існує багато способів вирішити це. Цікаво, чи хтось може допомогти почухати мої свербіння.


просто використовуйте словник, якщо ви хочете шукати на основі ключа .... BTW: ви можете використовувати індексатор для цього класу, але це зробить циклічно, тому немає виграшу
Карстен,

Відповіді:


181

Від MSDN :

Ця властивість повертає нуль у наступних випадках:

1) якщо вказаний ключ не знайдено;

Тож ви можете просто:

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

2) якщо вказаний ключ знайдений і пов’язане з ним значення є нульовим.

collection[key]викликає base.Get()те , base.FindEntry()що внутрішньо використовує Hashtableз продуктивністю O (1).


38
Ця властивість повертає нуль у таких випадках: 1) якщо вказаний ключ не знайдено; і 2) якщо вказаний ключ знайдений і пов'язане з ним значення є нульовим. Ця властивість не відрізняє двох випадків.
Стів

1
@Andreas, тому краще зберігати порожню рядок замість null
абатищев

@Steve OP нічого не говорить про таке зіткнення.
абатищев

13
Щоправда, @abatishchev, проте ОП каже, "перевірка наявності ключа". Прийняття нуля як ключа не існує, це неправда. Наприкінці немає відповіді без компромісу (без циклу, використовуйте порожні рядки)
Стів

@abatishchev, це як сказати, що 0дорівнює null... sry
Andreas Niedermair

54

Використовуйте цей метод:

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

    return true;
}

Це найефективніше NameValueCollectionі не залежить від того, чи містить колекція nullзначення чи ні.


5
Пам'ятайте про це using System.Linq;при використанні цього рішення.
jhauberg

14

Я не думаю, що будь-яка з цих відповідей є цілком правильною / оптимальною. NameValueCollection не тільки не розрізняє нульові значення і відсутні значення, але також нечутливий до регістру щодо його ключів. Таким чином, я думаю, що повним рішенням було б:

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

Мені подобається це рішення. Дивлячись на джерело NameValueCollectionBase, він за замовчуванням використовує InvariantCultureIgnoreCase, однак це не означає, що інший не передається для використання замість того, щоб будь-який клас створював екземпляр NameValueCollection.
lethek

12

Так, ви можете використовувати Linq для перевірки AllKeysвласності:

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

Однак a Dictionary<string, string[]>буде набагато більше підходить для цієї мети, можливо, створений методом розширення:

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
Це буде циклічно над усією колекцією, яка є O (n). У той час як collection[key]внутрішньо використовує Hashtableякий є O (1)
абатищев

4
@abatishchev Дійсно, однак, не collection[key]робить різниці між відсутнім ключем і нульовим значенням, яке зберігається проти цього ключа.
Річ О'Келлі

Також ви можете підготувати брудний злом і отримати приватне поле Hashtable за допомогою Reflection.
абатищев

Я думаю, що це досить дурне рішення. Якщо хтось використовує NameValueCollection, це може бути з причин, що словник не підтримується, наприклад, з нульовим ключем.
Кріс Марісіч

0

Ви можете використати Getметод і перевірити, nullяк метод повернеться, nullякщо NameValueCollection не містить вказаного ключа.

Див. MSDN .


Ви повинні знати , indexз keyвикликати метод. Чи не так?
абатищев

0

Якщо розмір колекції невеликий, ви можете скористатися рішенням, яке надає rich.okelly. Однак велика колекція означає, що генерація словника може бути помітно повільнішою, ніж просто пошук колекції ключів.

Крім того, якщо ваш сценарій використання шукає ключі в різні моменти часу, де NameValueCollection може бути змінено, щоразу створюючи словник, може бути повільніше, ніж просто пошук колекції ключів.


0

Це також може бути рішенням без необхідності впровадження нового методу:

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

0

Як ви бачите в довідкових джерелах, NameValueCollection успадковує від NameObjectCollectionBase .

Отже, ви берете базовий тип, отримуєте приватний хештел за допомогою відображення та перевіряєте, чи містить він конкретний ключ.

Щоб він також працював у Mono, вам потрібно побачити, яке ім'я хештелю є моно, що ви можете побачити тут (m_ItemsContainer), і отримати монополе, якщо початкове FieldInfo є нульовим (моно- час виконання).

Подобається це

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

для надчистого невідбиваючого коду .NET 2.0 ви можете перебирати ключі замість використання хеш-таблиці, але це повільно.

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

У VB це:

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

У C # повинно бути просто:

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

Не впевнений, що це повинно бути nullабо , ""але це повинно допомогти.


Вибачте, що є у VB. C # повинен бути, якщо (MyNameValueCollection (Key)! = Null) {} Не впевнений, чи має бути нуль або "", але це повинно допомогти.
CodeShouldBeEasy

Я вважаю, що правильний синтаксис схожий на Dictionaryструктуру даних, як у MyNameValueCollection[Key], а не MyNameValueCollection(Key), яка очікує виклику методу.
Blairg23

0

Я використовую цю колекцію, коли працював у колекції невеликих елементів.

Там, де елементів багато, я думаю, що потрібно використовувати "Словник". Мій код:

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

Або можна скористатися цим:

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

0
queryItems.AllKeys.Contains(key)

Майте на увазі, що ключ може бути не унікальним, і порівняння зазвичай чутливе до регістру. Якщо ви хочете просто отримати значення першого відповідного ключа і не турбуєтесь про регістр, використовуйте це:

        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
   }

Тип поверненого значення: System.Boolean вірно, якщо NameValueCollection містить ключі, які не є нульовими; в іншому випадку помилково. ПОСИЛАННЯ


2
Хоча це може відповісти на питання, деякі пояснення часто оцінюються, особливо для пояснення того, як це може бути хорошою альтернативою багатьом іншим відповідям.
Pac0

Це перевіряє, чи колекція містить якісь ключі. ОП попросила існувати певний ключ.
Білл Тюр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.