如何将 Cookies 集合转换为通用列表?容易地

Posted

技术标签:

【中文标题】如何将 Cookies 集合转换为通用列表?容易地【英文标题】:How do I convert the Cookies collection to a generic list? Easily 【发布时间】: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”类型

【问题讨论】:

【参考方案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));
  

【讨论】:

以上是关于如何将 Cookies 集合转换为通用列表?容易地的主要内容,如果未能解决你的问题,请参考以下文章

如何编写用于将分隔字符串转换为列表的通用扩展方法?

如何使用 json.net 将 c# 通用列表转换为 json?

如何使用 json.net 将 c# 通用列表转换为 json?

如何将集合转换为列表?

在这种情况下如何将集合转换为列表

.NET - 将通用集合转换为 DataTable