Проверьте, существует ли ключ в NameValueCollection
Есть ли быстрый и простой способ проверить, существует ли ключ в коллекции NameValueCollection, не проходя через него?
Ищете что-то вроде Dictionary.ContainsKey() или аналогичное.
Есть много способов решить это, конечно. Просто интересно, может ли кто-нибудь помочь мне почесать мозг?
12 ответов
Из 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).
Используйте этот метод:
private static bool ContainsKey(NameValueCollection collection, string key)
{
if (collection.Get(key) == null)
{
return collection.AllKeys.Contains(key);
}
return true;
}
Это самый эффективный для NameValueCollection
и не зависит от того, содержит ли коллекция null
ценности или нет.
Да, вы можете использовать Linq для проверки AllKeys
имущество:
using System.Linq;
...
collection.AllKeys.Contains(key);
Однако 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))
{
...
}
Я не думаю, что какой-либо из этих ответов является совершенно правильным / оптимальным. 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);
}
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;
}
Я использую эту коллекцию, когда я работал в коллекции небольших элементов.
Где элементов много, я думаю, нужно использовать "Словарь". Мой код:
NameValueCollection ProdIdes;
string prodId = _cfg.ProdIdes[key];
if (string.IsNullOrEmpty(prodId))
{
......
}
Или может быть использовать это:
string prodId = _cfg.ProdIdes[key] !=null ? "found" : "not found";
Если размер коллекции невелик, вы можете воспользоваться решением, предоставленным rich.okelly. Однако большая коллекция означает, что создание словаря может быть заметно медленнее, чем просто поиск в коллекции ключей.
Кроме того, если ваш сценарий использования выполняет поиск ключей в разные моменты времени, где коллекция NameValueCollection могла быть изменена, создание словаря каждый раз может, опять-таки, выполняться медленнее, чем просто поиск в коллекции ключей.
Как вы можете видеть в справочных источниках, NameValueCollection наследуется от NameObjectCollectionBase.
Таким образом, вы берете базовый тип, получаете частную хеш-таблицу с помощью отражения и проверяете, содержит ли она определенный ключ.
Для того, чтобы он работал и в Mono, вам нужно посмотреть, как называется хеш-таблица в mono, что вы можете увидеть здесь (m_ItemsContainer), и получить монополе, если начальное FieldInfo равно нулю (mono- во время выполнения).
Как это
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;
}
Это также может быть решением без необходимости введения нового метода:
item = collection["item"] != null ? collection["item"].ToString() : null;
Вы могли бы использовать Get
метод и проверка на null
как метод вернется null
если NameValueCollection не содержит указанный ключ.
Смотрите MSDN.
В VB это:
if not MyNameValueCollection(Key) is Nothing then
.......
end if
В C# должно быть просто:
if (MyNameValueCollection(Key) != null) { }
Не уверен, если это должно быть null
или же ""
но это должно помочь.
NameValueCollection n = Request.QueryString;
if (n.HasKeys())
{
//something
}
Возвращаемое значение Тип: System.Boolean Значение true, если коллекция NameValueCollection содержит ключи, которые не равны NULL; иначе ложно. ССЫЛКА НА САЙТ