2011-05-19 151 views
1

簡短問題:當我在viewstate中放入同一個對象的同一個實例兩次時,在反序列化時有兩個實例。我想只有一個例子。這可以做到,怎麼樣?爲什麼ASP.NET viewstate會丟失序列化對象的身份?

羅嗦解釋:

考慮下面的代碼:

public partial class MyControl : System.Web.UI.UserControl 
{ 
    [Serializable] 
    class MyClass 
    { 
     public string x; 
    } 
    public void Page_Load(object sender, EventArgs e) 
    { 
     if (this.IsPostBack) 
     { 
      MyClass a = (MyClass)this.ViewState["a"]; 
      MyClass b = (MyClass)this.ViewState["b"]; 
      MessageManager.Show((a == b).ToString(), MessageSeverity.Debug); 
     } 
     else 
     { 
      var x = new MyClass() { x = "stackoverflow" }; 
      this.ViewState["a"] = x; 
      this.ViewState["b"] = x; 
      MessageManager.Show("Init", MessageSeverity.Debug); 
     } 
    } 
} 

當它運行,並回傳被啓動時,我得到的消息, 「假」。也就是說,儘管我在視圖狀態中放置了一個對象,但它已經連續兩次了。這可以通過檢查視圖狀態內容來驗證。

如果我嘗試將交叉引用對象置於viewstate中,那麼每個項目都會被序列化爲單獨的圖形。舉例說明:

public partial class MyControl : System.Web.UI.UserControl 
{ 
    [Serializable] 
    class MyClass 
    { 
     public string x; 
     public MyClass other; 
    } 
    public void Page_Load(object sender, EventArgs e) 
    { 
     if (this.IsPostBack) 
     { 
      MyClass a = (MyClass)this.ViewState["a"]; 
      MyClass b = (MyClass)this.ViewState["b"]; 
      MessageManager.Show((a.other == b).ToString(), MessageSeverity.Debug); 
      MessageManager.Show((a.other.other == a).ToString(), MessageSeverity.Debug); 
     } 
     else 
     { 
      var a = new MyClass() { x = "stack" }; 
      var b = new MyClass() { x = "overflow" }; 
      a.other = b; 
      b.other = a; 
      this.ViewState["a"] = a; 
      this.ViewState["b"] = b; 
      MessageManager.Show("Init", MessageSeverity.Debug); 
     } 
    } 
} 

現在我得到消息「False」和「True」(按該順序)。再次,檢查Viewstate顯示,每個對象被序列化兩次。是什麼賦予了?我用ILSpy檢查了System.Web.UI.StateBag的源碼,但它只是將所有值推入ArrayList,並且沒有特殊的序列化代碼。所以,無論誰在序列化視圖狀態(System.Web.UI.ObjectStateFormatter?)都以某種方式將每個對象和序列化作爲一個單獨的圖表......爲什麼?我可以解決它嗎?

更新:我需要這個的原因是相同的對象將由兩個單獨的組件持久化,並且在反序列化時,我想檢查它們是否具有相同的對象。 (或者說,它們都存儲對象集合,我需要同步這些集合)。

我可以用十幾種不同的方式實現自定義比較,但是因爲我想爲任意對象執行此操作,所以它會變得棘手。 ;)

+0

@leppie - 那是多麼*特定*系列化工程;這並不一定適用於其他人 – 2011-05-19 09:06:53

回答

2

您可以覆蓋您的類的==運算符,或覆蓋Equals並通過a.Equals(b)執行比較以查看它們是否相同,而不是依賴基於地址的默認相等性。

+0

是的,我意識到這一點,但之後我需要爲我打算放在那裏的每個對象實施自定義比較。如果可能的話,我想要更優雅的東西。 – 2011-05-19 09:33:43

+0

是的,我認爲會是這種情況,只是指出明顯的情況下,如果有更好的解決方案不會出現,並有其他人未來經過。 – 2011-05-19 10:02:12

+0

我會接受你的回答,儘管我沒有重寫Equals,而是創建了一個自定義的IEqualityComparer。侵入性較小。 – 2011-05-19 13:31:54

2

Viewstate是一本字典,它是如何運作的。如果你想存儲相同的值,並且只有在寫入相同的「密鑰」時纔會覆蓋之前的值。

也沒有試圖通過做你的相等比較a.Equals(B)

+0

查看更新。我不明白爲什麼它會這樣操作。事實上,我認爲這很不直觀。如果我把兩樣東西放在一起,我希望兩次得到同樣的東西。它記錄在任何地方嗎? – 2011-05-19 09:33:15