短い質問:オブジェクトの同じインスタンスをビューステート内に 2 回配置すると、逆シリアル化時に 2 つのインスタンスが存在します。1 つのインスタンスだけが必要です。これはどのように行うことができますか?
冗長な説明:
次のコードを検討してください。
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);
}
}
}
それが実行され、ポストバックが開始されると、「false」というメッセージが表示されます。つまり、ビューステート内に 1 つのオブジェクトを配置しましたが、2 回シリアル化されました。これは、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 を調べると、各オブジェクトが 2 回シリアル化されていることがわかります。何を与える?のソースSystem.Web.UI.StateBag
を ILSpy で確認しましたが、すべての値を にプッシュするだけで、ArrayList
特別なシリアル化コードもありません。したがって、viewstate をシリアル化する人 ( System.Web.UI.ObjectStateFormatter
?) は、どういうわけか各オブジェクトを取得し、個別のグラフとしてシリアル化しています...なぜですか? そして、私はそれを回避できますか?
更新:これが必要な理由は、同じオブジェクトが 2 つの別々のコンポーネントによって永続化され、逆シリアル化時にそれらが同じオブジェクトを持っているかどうかを確認したいからです。(というか、どちらもオブジェクト自体のコレクションを格納しており、それらのコレクションを同期する必要があります)。
さまざまな方法でカスタム比較を実装できますが、これを任意のオブジェクトに対して実行したいので、ややこしくなります。;)