【问题标题】:Copy key values from NameValueCollection to Generic Dictionary将键值从 NameValueCollection 复制到通用字典
【发布时间】:2013-05-09 02:56:14
【问题描述】:

试图将值从现有的 NameValueCollection 对象复制到字典。我有下面的代码可以做到这一点,但似乎 Add 不接受我的键和值是字符串

IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
public void copyFromNameValueCollection (NameValueCollection a)
{
    foreach (var k in a.AllKeys)
    { 
        dict.Add(k, a[k]);
    }  
}

注意: NameValueCollection 包含字符串键和值,因此我只想在这里提供一种方法,允许将它们复制到 generic 字典。

【问题讨论】:

  • 这很令人困惑,因为大概这是在一个通用的 type 中声明 TKey, TValue 类型参数 - 而你的 method 声明了这些类型参数。再加上键将始终是字符串的事实......那么如果 TKey 是(比如说)Guid,你期望会发生什么?
  • 我需要一个通用字典。请注意,这是在构建一个可序列化的字典类,它还允许从 NameValueCollection 对象中复制键和值
  • 再一次,如果 TKey 不是字符串会怎样?

标签: c# .net dictionary namevaluecollection


【解决方案1】:

您不应该忘记 EqualityComparer。但它不是公共财产。所以,你应该使用反射来获取它。

public static IEqualityComparer GetEqualityComparer(this NameObjectCollectionBase nameObjectCollection)
  {
  PropertyInfo propertyInfo = typeof(NameObjectCollectionBase).GetProperty("Comparer", BindingFlags.Instance | BindingFlags.NonPublic);
  return (IEqualityComparer)propertyInfo.GetValue(nameObjectCollection);
  }

public static IEqualityComparer<string> GetEqualityComparer(this NameValueCollection nameValueCollection)
  {
  return (IEqualityComparer<string>)((NameObjectCollectionBase)nameValueCollection).GetEqualityComparer();
  }

public static Dictionary<string, string> ToDictionary(this NameValueCollection nameValueCollection)
  {
  Dictionary<string, string> dictionary =
    nameValueCollection.AllKeys.ToDictionary(x => x, x => nameValueCollection[x], nameValueCollection.GetEqualityComparer());
  return dictionary;
  }

【讨论】:

    【解决方案2】:
    parameters.AllKeys.ToDictionary(t => t, t => parameters[t]);
    

    【讨论】:

    • 喜欢这个。谢谢!
    • kt 更有意义来表示“键”
    【解决方案3】:

    在这里使用泛型没有意义,因为您不能将strings 分配给任意泛型类型:

    IDictionary<string, string> dict = new Dictionary<string, string>();
    
    public void copyFrom(NameValueCollection a)
    {
                foreach (var k in a.AllKeys)
                { 
                    dict.Add(k, a[k]);
                }  
    }
    

    虽然您可能应该创建一个方法来创建新字典:

    public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
    {
        IDictionary<string, string> dict = new Dictionary<string, string>();
        foreach (var k in col.AllKeys)
        { 
            dict.Add(k, col[k]);
        }  
        return dict;
    }
    

    你可以像这样使用:

    NameValueCollection nvc = //
    var dictionary = nvc.ToDictionary();
    

    如果您想要一种将集合中的字符串转换为所需键/值类型的通用方法,您可以使用类型转换器:

    public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this NameValueCollection col)
    {
        var dict = new Dictionary<TKey, TValue>();
        var keyConverter = TypeDescriptor.GetConverter(typeof(TKey));
        var valueConverter = TypeDescriptor.GetConverter(typeof(TValue));
    
        foreach(string name in col)
        {
            TKey key = (TKey)keyConverter.ConvertFromString(name);
            TValue value = (TValue)valueConverter.ConvertFromString(col[name]);
            dict.Add(key, value);
        }
    
        return dict;
    }
    

    【讨论】:

    • NameValueCollection 具有字符串键和值。我希望能够将它们复制到通用字典中。
    • @Kobojunkie - 您不能将其复制到通用字典中,因为键和值类型可以是任何类型。您只能将其复制到 Dictionary&lt;string, string&gt; 或具有较少派生的键或值类型的一个,例如object.
    • @Kobojunkie - 当然是正确的 - 对于 any 类型 T,您不能说 T obj = "abc"。只有当Tstring 或派生较少的类型时,它才会编译。您可以将字符串转换为目标类型,但您的问题并不清楚。
    • @Kobojunkie - 我添加了一种将集合中的键/值转换为目标类型的通用方法。
    • 我以为你之前说过不可能?
    【解决方案4】:

    超短版

    var dataNvc = HttpUtility.ParseQueryString(data);
    var dataCollection = dataNvc.AllKeys.ToDictionary(o => o, o => dataNvc[o]);
    

    【讨论】:

      【解决方案5】:

      扩展方法加linq:

       public static Dictionary<string, string> ToDictionary(this NameValueCollection nvc) {
          return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]);
       }
      
       //example
       var dictionary = nvc.ToDictionary();
      

      【讨论】:

        【解决方案6】:

        使用 LINQ:

        public static IDictionary<string, string> ToDictionary(this NameValueCollection collection)
        {
            return collection.Cast<string>().ToDictionary(k => k, v => collection[v]);
        }
        

        用法:

        IDictionary<string, string> dic = nv.ToDictionary();
        

        【讨论】:

          【解决方案7】:

          如果您知道字典总是包含字符串,请将其指定为包含字符串,而不是使您的类成为通用类:

          IDictionary<string, string> dict = new Dictionary<string, string>();
          

          有了这个,事情就会像写的那样“正常工作”(没有通用方法规范)。

          如果您需要它成为一个泛型类并保存泛型数据,您需要某种方法将string 转换为TKeystring 转换为TValue。您可以为您的复制方法提供委托来执行此操作:

          public void CopyFrom(NameValueCollection a, Func<string, TKey> keyConvert, Func<string, TValue> valueConvert)
          {
              foreach(var k in a.AllKeys)
              {
                   dict.Add(keyConvert(k), valueConvert(a[k]));
              }
          }
          

          然后您需要传递一个委托来执行从字符串到TValue 和字符串到TKey 的转换。

          【讨论】:

          • 这个答案应该提到NameValueCollections 可以有空键,并且在转换为具有非空键不变量的字典时必须考虑这种不匹配
          • 字典并不总是包含字符串。我只是希望它也能够在此方法中从 NameValueCollection 对象中复制值。
          • @Kobojunkie 然后你需要第二种机制 - 你需要从字符串转换为你的类型
          • 这就是我在这里寻求帮助的原因。如何在此方法中将 NameValueCollection 中的字符串键和值转换为泛型类型,以便将它们加载到我的泛型字典对象中
          • @Kobojunkie 没有“通用”方法可以做到这一点 - 您需要某种类型的方法来进行转换。我的第二个选项显示了如何编写方法,以便可以将其作为委托传递。
          猜你喜欢
          • 1970-01-01
          • 2020-01-03
          • 1970-01-01
          • 2011-04-16
          • 2015-05-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多