.NET深入学习之---一个不是Bug的Bug

   我的上一篇随笔<.NET Framework源码研究系列之---Delegate>中提到.NET事件的一个Bug.今天整理出来跟大家一起分享一下,顺便请大家说说自己的看法.

      不说别的,先看测试代码:    

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
1 using System;
2   using System.IO;
3   using System.Runtime.Serialization;
4   using System.Runtime.Serialization.Formatters.Soap;
5
6   namespace OneBug
7 {
8 class Program
9 {
10 static void Main( string [] args)
11 {
12 try
13 {
14 TestItem tt = new TestItem();
15 UserClass us = new UserClass(tt);
16 tt.Invoke();
17 using (Stream stream = new FileStream( " MyFile.bin " , FileMode.Create, FileAccess.Write, FileShare.None))
18 {
19 IFormatter formatter = new SoapFormatter();
20 formatter.Serialize(stream, tt);
21 stream.Close();
22 }
23 Console.Read();
24 }
25 catch (Exception ex)
26 {
27 Console.WriteLine(ex.Message);
28 }
29 }
30 }
31 [Serializable]
32 public class TestItem
33 {
34 public int _Field1 = 10 ;
35 public event EventHandler OnChange;
36 public TestItem() { }
37 public void Invoke()
38 {
39 if (OnChange != null )
40 OnChange( this , null );
41 }
42 }
43 // [Serializable]
44   public class UserClass
45 {
46 public string _UserName = " 倪大虾 " ;
47 public TestItem _Item;
48 public UserClass(TestItem item)
49 {
50 _Item = item;
51 item.OnChange += new EventHandler(item_OnChange);
52 }
53 void item_OnChange( object sender, EventArgs e)
54 {
55 Console.WriteLine( this ._UserName);
56 }
57 }
58 }

上面一段代码看起来没有问题,但是编译的时候会有如下错误:

2010072320230881.png

如果把44行前面的"//"去掉,则没有问题,反序列化成功.这时我们打开序列化的文件看下里面的内容,如下:

<a1:TestItem id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/OneBug/OneBug%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_Field1>20</_Field1>
<OnChange href="#ref-3"/>
</a1:TestItem>

.....
<a1:UserClass id="ref-5" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/OneBug/OneBug%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<_UserName id="ref-13">倪大虾</_UserName>
</a1:UserClass>

是不是觉得很神气呢,对象tt序列化的时候居然连同对象us一同序列化了.

 

到这里问题就很明白了,至少看起来应该是UserClass的实例us保存有TestItem的实例tt的一个引用.就算序列化时需要将一个实例的引用对象一起序列化,那也应该是序列化us时出现的现象(事实却是如此),而不应该是此类状况.看下面的测试代码:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
1 using System;
2   using System.IO;
3   using System.Runtime.Serialization;
4   using System.Runtime.Serialization.Formatters.Soap;
5
6   namespace OneBug{
7 class Program{
8 static void Main( string [] args){
9 try {
10 Class2 c2 = new Class2();
11 using (Stream stream = new FileStream( " MyFile21.bin " , FileMode.Create, FileAccess.Write, FileShare.None))
12 {
13 IFormatter formatter = new SoapFormatter();
14 formatter.Serialize(stream, c2.c1);
15 stream.Close();
16 }
17 Console.Read();
18 }
19 catch (Exception ex){
20 Console.WriteLine(ex.Message);
21 }
22 }
23 }
24 [Serializable]
25 public class Class1 {
26 public int f1 = 1000 ;
27 }
28 [Serializable]
29 public class Class2 {
30 public string s1 = " niyw " ;
31 public Class1 c1 = new Class1();
32 }
33 }

此段代码中c2.c1的序列化结果为

<SOAP-ENV:Body>
<a1:Class1 id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/OneBug/TwoBug%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<f1>1000</f1>
</a1:Class1>

丝毫没有Class2的实体c2的影子.

 

  至此,显然我们发现了一个问题,那就是为什么tt的序列化文件中会包含us的序列化内容?

     难道是微软的Bug吗?!看起来像.不过联系<.NET Framework源码研究系列之---Delegate>中的观点,我们就不难理解这个现象了.TestItem的实例tt中包含了一个事件(Event)OnChange,而这个事件包含了UserClass的实例us的引用.所以在序列化tt的时候连同us一起序列化了.这点也可以从序列化文件中看出端倪,我从中找出了如下内容:

....

<a2:DelegateSerializationHolder id="ref-5" xmlns:a2="http://schemas.microsoft.com/clr/ns/System">
<Delegate href="#ref-6"/>
<target0 href="#ref-1"/>
<method0 href="#ref-7"/>
</a2:DelegateSerializationHolder>
<a2:DelegateSerializationHolder_x002B_DelegateEntry id="ref-6" xmlns:a2="http://schemas.microsoft.com/clr/ns/System">
<type id="ref-8">System.EventHandler</type>
<assembly id="ref-9">mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly>
<target id="ref-10" xsi:type="SOAP-ENC:string">target0</target>
<targetTypeAssembly id="ref-11">TwoBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</targetTypeAssembly>
<targetTypeName id="ref-12">OneBug.UserClass</targetTypeName>
<methodName id="ref-13">item_OnChange</methodName>
<delegateEntry xsi:null="1"/>

 ... 

  随便写到此处,相比大家明白了文章一开始出现的错误,和对.NET的委托有更深入的了解.

 

  但是,此处仍有问题让我想不明白.那就是如果我们对tt进行反序列化获得一个TestItem的实例,其中定然有一个UserClass的实例,那么我们如何获取到它呢?如果获取了,又有什么意义呢? 有机会大家一起研究,今天就到此结束了.:)

转载于:https://www.cnblogs.com/niyw/archive/2010/07/23/1784017.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值