【问题标题】:How do I convert the Cookies collection to a generic list? Easily如何将 Cookies 集合转换为通用列表?容易地
【发布时间】:2011-02-24 18:01:34
【问题描述】:

任何人都知道如何将Request.Cookies 转换为List<HttpCookie>?以下内容不起作用,因为它引发了异常。

List<HttpCookie> lstCookies = new List<HttpCookie>(
    Request.Cookies.Cast<HttpCookie>());

异常:无法将“System.String”类型的对象转换为“System.Web.HttpCookie”类型

【问题讨论】:

    标签: .net generics .net-3.5


    【解决方案1】:

    发生这种情况的原因是Request.Cookies 派生的NameObjectCollectionBase 类型枚举集合的键而不是值。因此,当您枚举 Request.Cookies 集合时,您将获得密钥:

    public virtual IEnumerator GetEnumerator()
    {
        return new NameObjectKeysEnumerator(this);
    }
    

    这意味着以下将起作用:

    string[] keys = Request.Cookies.Cast<string>().ToArray();
    

    我想您可以尝试以下可能被认为丑陋但会起作用的方法:

    List<HttpCookie> lstCookies = Request.Cookies.Keys.Cast<string>()
        .Select(x => Request.Cookies[x]).ToList();
    

    更新:

    正如@Jon Benedicto 在 cmets 部分和在 his answer 中所指出的,使用 AllKeys 属性更为理想,因为它可以节省演员表:

    List<HttpCookie> lstCookies = Request.Cookies.AllKeys
        .Select(x => Request.Cookies[x]).ToList();
    

    【讨论】:

    • 但是你失去了键 -> 值连接:)
    • @Snake,我同意你的观点,从性能的角度来看这不是最佳的,因为它会多次枚举集合,但如果你有几个元素,它可能不会引人注目。
    • 使用 HttpCookieCollection 的 AllKeys 成员可以节省演员表。请参阅我的代码答案。
    • 这帮助我解决了 XmlSerializer 序列化键而不是值的问题。我的 NameObjectCollectionBase 子类需要将 GetEnumerator 覆盖为 return this.BaseGetValues().GetEnumerator();
    【解决方案2】:

    如果你真的想要一个没有 key->value 连接的直接List&lt;HttpCookie&gt;,那么你可以使用 LINQ 中的 Select 来做到这一点:

    var cookies = Request.Cookies.AllKeys.Select(x => Request.Cookies[x]).ToList();
    

    【讨论】:

    • 如果 cookie 是在不同的域中创建的,IE 可以发送多个具有相同名称的 cookie。如果发生这种情况,那么上面的代码会丢失其中一个 cookie。
    • 代码只获取第一个同名cookie。
    【解决方案3】:

    .Cookies.Cast&lt;HttpCookie&gt;(); 尝试将键集合转换为 cookie 集合。所以你得到一个错误是正常的:)

    这是一个名称 -> 值集合,因此转换为列表并不好。

    我会尝试将其转换为字典。

    例如:

    由于 Cookies 继承自 NameObjectCollectionBase,您可以GetAllKeys(),并使用该列表获取所有值并将它们放入字典中。

    例如:

    Dictionary cookieCollection = new Dictionary<string, object>();
    
    foreach(var key in Request.Cookies.GetAllKeys())
    {
        cookieCollection.Add(key, Request.Cookies.Item[key]);
    }
    

    【讨论】:

      【解决方案4】:

      这个问题可能有点老了,但这里的答案并不涵盖所有情况,因为正如@C.M.所指出的那样。可以有多个同名的 cookie。

      所以最简单的方法是使用 for 循环来循环 cookie 集合:

      var existingCookies = new List<HttpCookie>();
      
      for (var i = 0; i < _httpContext.Request.Cookies.Count; i++)
      {
          existingCookies.Add(_httpContext.Request.Cookies[i]);
      }
      

      【讨论】:

        【解决方案5】:

        您可以通过使用集合的 CountEnumerable.Range 来避免迭代键。

        using System.Collections.Generic;
        using System.Linq;
        using System.Web;
        
        namespace Foo
        {
          public static class WebHttpExtensions
          {
            public static IEnumerable<HttpCookie> AsEnumerable(this HttpCookieCollection webCookies) =>
              Enumerable
                .Range(0, webCookies.Count)
                .Select(ndx => webCookies[ndx]);
        
            public static IEnumerable<System.Net.Cookie> ToNetCookies(this HttpCookieCollection webCookies) => 
              webCookies
                .AsEnumerable()
                .Select(x => new System.Net.Cookie(x.Name, x.Value));
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-10-09
          • 1970-01-01
          • 1970-01-01
          • 2011-01-29
          • 1970-01-01
          • 2013-12-16
          • 2010-10-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多