Проверьте, существует ли ключ в NameValueCollection

Есть ли простой и простой способ проверить, существует ли ключ в NameValueCollection без его прокрутки?

Ищите что-то вроде Dictionary.ContainsKey() или аналогичного.

Конечно, есть много способов решить эту проблему. Просто интересно, может ли кто-нибудь помочь поцарапать мой мозг зудом.

Ответ 1

От MSDN:

Это свойство возвращает null в следующих случаях:

1), если указанный ключ не найден;

Итак, вы можете просто:

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

2), если указанный ключ найден, и его связанное значение равно null.


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

Ответ 2

Используйте этот метод:

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

    return true;
}

Он наиболее эффективен для NameValueCollection и не зависит от того, имеет ли коллекция коллекция null значения или нет.

Ответ 3

Я не думаю, что любой из этих ответов вполне правильный/оптимальный. 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);
}

Ответ 4

Да, вы можете использовать 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))
{
   ...
}

Ответ 5

NameValueCollection n = Request.QueryString;

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

Ответ 6

Вы можете использовать метод Get и проверить на null, поскольку метод вернет null, если NameValueCollection не содержит указанный ключ.

См. MSDN.

Ответ 7

Если размер коллекции мал, вы можете пойти с решением, предоставленным rich.okelly. Однако большая коллекция означает, что генерация словаря может быть заметно медленнее, чем просто поиск коллекции ключей.

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

Ответ 8

Это также может быть решением без необходимости вводить новый метод:

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

Ответ 9

Как вы можете видеть в исходных источниках, NameValueCollection наследует от NameObjectCollectionBase.

Итак, вы берете базовый тип, получаете личную хэш-таблицу через отражение и проверяете, содержит ли он конкретный ключ.

Чтобы он работал в Mono, вам нужно посмотреть, что имя хэш-таблицы в моно, что вы можете увидеть здесь (m_ItemsContainer) и получить монополе, если исходное поле FieldInfo равно null (моно-время выполнения).

Подобно этому

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

Ответ 10

В VB это:

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

В С# должно быть только:

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

Не уверен, что это должно быть null или "", но это должно помочь.