Проверьте, существует ли ключ в 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
или ""
, но это должно помочь.