检查NameValueCollection中是否存在键


141

有没有一种快速简单的方法来检查键是否存在于NameValueCollection中而无需遍历它?

寻找类似Dictionary.ContainsKey()之类的东西。

当然,有很多方法可以解决此问题。只是想知道是否有人可以帮助我挠痒。


如果您想基于关键字进行查找,则只需使用Dictionary ....顺便说一句:您可以在此类上使用索引器,但这将自行循环-这样就没有好处
Carsten 2012年

Answers:


181

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)进行调用。


37
在以下情况下,此属性返回null:1)如果找不到指定的键;2)如果找到了指定的键,并且其关联的值为null。此属性不能区分这两种情况。
史蒂夫

1
@Andreas这就是为什么它是更好的空字符串代替空存储
abatishchev

@Steve OP没有对这种碰撞发表任何评论。
abatishchev 2012年

13
对@abatishchev,但是OP会说“检查密钥是否存在”。将null作为键不存在是不正确的。最后,没有妥协就没有答案(没有循环,请使用空字符串)
Steve

@abatishchev就像是说0等于null... sry
Andreas Niedermair 2012年

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 2012年

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 2015年

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)
abatishchev 2012年

4
@abatishchev但是collection[key],确实没有在不存在的密钥和针对该密钥存储的空值之间进行区分。
Rich O'Kelly 2012年

此外,您还可以执行肮脏的黑客攻击,并使用Reflection检索Hashtable的私有字段。
abatishchev 2012年

我认为这是一个非常愚蠢的解决方案。如果有人使用NameValueCollection,则可能是由于不支持字典的原因,例如具有null键。
克里斯·马里西克


0

如果集合很小,则可以使用rich.okelly提供的解决方案。但是,大集合意味着字典的生成可能比仅搜索键集合慢得多。

另外,如果您的使用场景是在不同的时间点搜索键,则NameValueCollection可能已被修改,那么每次生成字典的速度可能比仅搜索键集合要慢。


0

这也可以是解决方案,而不必引入新方法:

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

0

如您在参考源中看到的,NameValueCollection继承自NameObjectCollectionBase

因此,您采用基本类型,通过反射获取私有哈希表,并检查它是否包含特定键。

为了使它在Mono中也能正常工作,您需要查看哈希表在mono中的名称,这是您可以在此处(m_ItemsContainer)看到的内容,如果初始FieldInfo为null(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;
}

0

在VB中是:

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

在C#中应该是:

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

不知道是否应该null""但这应该有所帮助。


抱歉,在VB中。C#应该只是if(MyNameValueCollection(Key)!= null){}不知道它应该为null还是“”,但这应该有所帮助。
CodeShouldBeEasy

我相信正确的语法类似于,而不是中的Dictionary数据结构,它需要一个方法调用。MyNameValueCollection[Key]MyNameValueCollection(Key)
布莱格23年

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包含不为null的键,则为true;否则为false。否则为假。链接


2
尽管这可以回答问题,但通常会得到一些解释,尤其是要解释这可能是许多其他答案的很好替代方法。
Pac0

这仅检查集合中是否根本包含任何键。OP要求存在某个密钥。
比尔·图尔(BillTür)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.