【问题标题】:Check if Key Exists in NameValueCollection检查 NameValueCollection 中是否存在键
【发布时间】:2022-04-20 07:06:31
【问题描述】:

有没有一种快速简单的方法来检查一个键是否存在于 NameValueCollection 中而不用循环遍历它?

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

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

【问题讨论】:

  • 如果您想根据键进行查找,只需使用 Dictionary ...。顺便说一句:您可以在此类上使用索引器,但这会自行执行循环- 所以没有收获

标签: c# .net namevaluecollection


【解决方案1】:

来自MSDN

此属性在以下情况下返回 null:

1) 如果没有找到指定的key;

所以你可以:

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

2) 如果找到指定的键并且其关联值为空。

collection[key] 调用 base.Get() 然后 base.FindEntry() 内部使用 Hashtable 性能 O(1)。

【讨论】:

  • 该属性在以下情况下返回null: 1)如果指定的key没有找到; 2) 如果找到指定的键并且其关联值为空。此属性不区分这两种情况。
  • @Andreas 这就是为什么最好存储空字符串而不是 null
  • @Steve OP 没有说明这种碰撞。
  • 对@abatishchev,但是 OP 说“检查密钥是否存在”。将 null 作为键不存在是不正确的。最后没有妥协就没有答案(没有循环,使用空字符串)
  • @abatishchev 这就像说0 等于null... sry
【解决方案2】:

此方法处理 key 在集合中且其关联值为 null 的情况。

private static bool ContainsKey(this NameValueCollection collection, string key) =>
    collection.Get(key) is not null || collection.AllKeys.Contains(key);

从 C# 9 开始你可以使用is not null,否则使用!= null

【讨论】:

  • 使用此解决方案时记得using System.Linq;
【解决方案3】:

是的,您可以使用 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))
{
   ...
}

【讨论】:

  • 这将遍历整个集合,即 O(n)。而collection[key] 内部使用Hashtable,即 O(1)
  • @abatishchev 确实,但是collection[key] 没有区分键不存在和针对该键存储的空值。
  • 你也可以使用反射来执行肮脏的黑客攻击并检索 Hashtable 的私有字段。
  • 我认为这是一个非常愚蠢的解决方案。如果有人使用 NameValueCollection,可能是由于不支持字典的原因,例如具有空键。
【解决方案4】:

我认为这些答案中的任何一个都不是非常正确/最佳的。 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 实例的类都不会传入不同的源来使用。
【解决方案5】:
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;
        }

【讨论】:

    【解决方案6】:

    您可以使用Get 方法并检查null,因为如果NameValueCollection 不包含指定的键,该方法将返回null

    MSDN

    【讨论】:

    • 您需要知道indexkey 才能调用该方法。不是吗?
    【解决方案7】:

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

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

    【讨论】:

      【解决方案8】:

      这也可以是一个无需引入新方法的解决方案:

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

      【讨论】:

        【解决方案9】:

        正如您在参考资料中所见,NameValueCollection 继承自 NameObjectCollectionBase

        所以你取基本类型,通过反射获取私有哈希表,并检查它是否包含特定键。

        为了让它也能在 Mono 中工作,您需要查看单声道中哈希表的名称是什么,您可以看到 here (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;
        }
        

        【讨论】:

          【解决方案10】:

          在 VB 中是:

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

          在 C# 中应该只是:

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

          不确定应该是null 还是"",但这应该会有所帮助。

          【讨论】:

          • 抱歉,这是在 VB 中。 C# 应该只是 if (MyNameValueCollection(Key) != null) { } 不确定它应该是 null 还是 "" 但这应该会有所帮助。
          • 我认为正确的语法类似于Dictionary 数据结构,如MyNameValueCollection[Key],而不是MyNameValueCollection(Key),它需要方法调用。
          【解决方案11】:

          我正在使用这个集合,当我在小元素集合中工作时。

          元素很多,我认为需要使用“字典”。 我的代码:

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

          或者可以使用这个:

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

          【讨论】:

            【解决方案12】:
            NameValueCollection n = Request.QueryString;
            
            if (n.HasKeys())
               {
                   //something
               }
            

            返回值 类型:System.Boolean 如果 NameValueCollection 包含不为空的键,则为 true;否则为假。 LINK

            【讨论】:

            • 虽然这可能会回答问题,但通常会受到一些解释,特别是解释这如何成为许多其他答案的好选择。
            • 这仅检查集合是否包含任何键。 OP 要求存在一个 certain 键。
            猜你喜欢
            • 2019-11-27
            • 1970-01-01
            • 1970-01-01
            • 2023-03-30
            • 2015-12-04
            • 2012-09-08
            • 1970-01-01
            • 2021-06-27
            • 1970-01-01
            相关资源
            最近更新 更多