• 为什么foreach(HttpCookie cookie in Request.Cookies)会出错


        第一次使用foreach(HttpCookie cookie in Request.Cookies)的时候, 我怎么也没想到它会出错,错误信息竟然是“指定的转换无效。”。Request.Cookies的类型是HttpCookieCollection,怎么会出错呢?HttpCookieCollection难道有与众不同的地方?
        既然不能转换,那cookie究竟是什么类型?我们用代码测试一下:
       
    foreach(object cookie in Request.Cookies)
                
    {
                    Response.Write(cookie.GetType().ToString()
    +"<br>");
                }

    原来cookie全变成了System.String类型, 上面的cookie变量的值就是Request.Cookies中每个Cookie的Name。下面的两段代码,结果是一样的:
     
    foreach(object cookie in Request.Cookies)
                
    {
                    Response.Write(cookie
    +"<br>");
                }

    foreach(string cookie in Request.Cookies.AllKeys)
                
    {
                    Response.Write(cookie
    +"<br>");
                }


    那我们如何枚举Request.Cookies?通过索引,我也不用多说了,大家都知道。  

    for(int i=0;i<Request.Cookies.Count;i++)
                
    {
                    Response.Write(Request.Cookies[i].Name
    +":"+Request.Cookies[i].Value+"<br>");
                }


    而Syste.Net.CookieCollection不存在这个问题,那HttpCookieCollection与CookieCollection有什么区别呢?我们比较一下它们的基类与接口:
    HttpCookieCollection 继承了NameObjectCollectionBase,NameObjectCollectionBase实现了ICollection, IEnumerable, ISerializable, IDeserializationCallback接口
    CookieCollection实现了ICollection, IEnumerable接口

    我想应该在NameObjectCollectionBase中可以找到答案。
    首先我们复习一下foreach的工作原理,先看下面的代码:

    namespace Test
    {
    class Class1
    {
       
    static void Main(string[] args)
       
    {
          
    ArrayList array = new ArrayList();
          array.Add(
    "A");
          array.Add(
    "B");
          array.Add(
    "C");

          
    foreach (string item in array)
          
    {
             Console.WriteLine(item);
          }

       }

    }


    在编译的时候,C#编辑器会对每一个foreach 区域进行转换,转换成下面的代码:


    IEnumerator enumerator = array.GetEnumerator();
    try 
    {
       
    string item;
       
    while (enumerator.MoveNext()) 
       
    {
          item 
    = (string) enumerator.Current;
          Console.WriteLine(item);
       }

    }

    finally 
    {
       IDisposable d 
    = enumerator as IDisposable;
       
    if (d != null) d.Dispose();
    }

    对于foreach(HttpCookie cookie in Request.Cookies), 转换的结果应该是这样:

    IEnumerator enumerator = HttpCookieCollection.GetEnumerator();
    try 
    {
       HttpCookie item;
       
    while (enumerator.MoveNext()) 
       
    {
          item 
    = (HttpCookie) enumerator.Current;
        }

    }

    finally 
    {
       IDisposable d 
    = enumerator as IDisposable;
       
    if (d != null) d.Dispose();
    }


    因为上面的enumerator.Current返回的是System.String类型,所以会出现“指定的转换无效”的错误。
    用Reflector查看NameObjectCollectionBase的源代码,可以发现 HttpCookieCollection.GetEnumerator()调用的是NameObjectCollectionBase中的GetEnumerator(),而GetEnumerator()返回的是NameObjectCollectionBase内部的一个类NameObjectKeysEnumerator的实例,这个类实现了IEnumerator。 
    上面的enumerator.Current实际上是调用的NameObjectKeysEnumerator的Current属性,而Current属性中又调用了NameObjectCollectionBase的BaseGetKey。头都昏了! 为了找到问题的真正原因,只能继续。BaseGetKey的代码是这样的:

    protected string BaseGetKey(int index)
    {
          NameObjectCollectionBase.NameObjectEntry entry1 
    = (NameObjectCollectionBase.NameObjectEntry) this._entriesArray[index];
          
    return entry1.Key;
    }

     


    答案终于找到,NameObjectCollectionBase返回的是NameObjectEntry(这也是NameObjectCollectionBase的一个内部类)的一个成员Key, 这个Key就是string类型的。
    问题的原因虽然找到,但为什么要这样设计,暂时还搞不明白,只能等以后慢慢研究。当然,如果有高人解惑就最好了。

  • 相关阅读:
    Core Data入门
    web前端开发与iOS终端开发的异同
    Blocks编程
    ARC下循环引用的问题
    小项目
    error: /Users/**/Documents/workspace/***/clean_right_normal.png: No such file or directory
    修复NSTextAlignmentCenter引起的警告
    Implicit conversion loses integer precision: 'long long' to 'NSUInteger' (aka 'unsigned int')
    手势相关函数
    implicit declaration of function setxattr is invalid in c99
  • 原文地址:https://www.cnblogs.com/dudu/p/80118.html
Copyright © 2020-2023  润新知