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

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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错foreach(string cookie in Request.Cookies.AllKeys)
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错                Response.Write(cookie
+"<br>");
为什么foreach(HttpCookie cookie in Request.Cookies)会出错            }


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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错for(int i=0;i<Request.Cookies.Count;i++)
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错                Response.Write(Request.Cookies[i].Name
+":"+Request.Cookies[i].Value+"<br>");
为什么foreach(HttpCookie cookie in Request.Cookies)会出错            }


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

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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错namespace Test
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错
class Class1
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   
static void Main(string[] args)
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      
ArrayList array = new ArrayList();
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      array.Add(
"A");
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      array.Add(
"B");
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      array.Add(
"C");
为什么foreach(HttpCookie cookie in Request.Cookies)会出错
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      
foreach (string item in array)
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错         Console.WriteLine(item);
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      }

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

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


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


为什么foreach(HttpCookie cookie in Request.Cookies)会出错IEnumerator enumerator = array.GetEnumerator();
为什么foreach(HttpCookie cookie in Request.Cookies)会出错
try 
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   
string item;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   
while (enumerator.MoveNext()) 
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      item 
= (string) enumerator.Current;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      Console.WriteLine(item);
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   }

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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错
finally 
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   IDisposable d 
= enumerator as IDisposable;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   
if (d != null) d.Dispose();
为什么foreach(HttpCookie cookie in Request.Cookies)会出错}

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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错IEnumerator enumerator = HttpCookieCollection.GetEnumerator();
为什么foreach(HttpCookie cookie in Request.Cookies)会出错
try 
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   HttpCookie item;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   
while (enumerator.MoveNext()) 
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      item 
= (HttpCookie) enumerator.Current;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错    }

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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错
finally 
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   IDisposable d 
= enumerator as IDisposable;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错   
if (d != null) d.Dispose();
为什么foreach(HttpCookie cookie in Request.Cookies)会出错}


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

为什么foreach(HttpCookie cookie in Request.Cookies)会出错protected string BaseGetKey(int index)
{
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      NameObjectCollectionBase.NameObjectEntry entry1 
= (NameObjectCollectionBase.NameObjectEntry) this._entriesArray[index];
为什么foreach(HttpCookie cookie in Request.Cookies)会出错      
return entry1.Key;
为什么foreach(HttpCookie cookie in Request.Cookies)会出错}

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


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

相关文章: