2009年5月21日 星期四

c# serizable碰到的小問題

今天在弄一個Serializable的物件的時候 執行時期Serialize竟然出現了以下的錯誤

類型 'System.Runtime.Serialization.SerializationException' 的未處理例外狀況發生於 mscorlib.dll
其他資訊: 未將型別 'WindowsApplication1.Form1' (於組件 'WindowsApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 中) 標記為可序列化。


奇怪 我明明有在物件前面冠上[Serializable]了阿 仔細一看 怎麼會是Form1沒有序列化
回頭去看程式碼 原來這物件在執行的時候有使用委派定時向UI thread更新情況 所以這物件的class裡有這樣兩個member
//向窗體發送消息的委托
public delegate void DelegateOfSendMessage(int Epochs, double Error);
public event DelegateOfSendMessage SendMessage;
所以神奇的地方發生了 這個物件的event會像UI thread也就是Form1註冊事件以回報更新進度
在Serialize的時候就會參考到form1 但是我們的form1沒有[Serializable] 所以就錯了

更神奇的是 平常我們不想序列化的member我們都會加[NonSerialized]來避免它一起序列化
可是如果在event前面加上[NonSerialized]

[NonSerialized] public event DelegateOfSendMessage SendMessage;

就會出現以下這種錯誤

屬性 'NonSerialized' 在此宣告型別上無效。它只在 'field' 宣告上有效。

最後解決辦法就是 在要Serialize之前 把event委派給清空 這樣就不會有問題了
正確程式碼片段如下

IFormatter binFmt = new BinaryFormatter();
Stream s = File.Open(path, FileMode.Create);
this.SendMessage = null;//在要Serialize之前 把event委派給清空
binFmt.Serialize(s, this);
s.Close();

1 意見:

張貼留言
Scott's Blog 提到...

這幾天正好也在研究這個功能,也遇到同樣的問題。

這邊有另外一個解決的方法...

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/3f8
feec6-cb1c-4971-ba51-9ef17e381b1c/