2012-02-15 8 views
4

ToListオプションを使用して辞書の値をシリアル化しようとしました。 デシリアライズ処理で、私がシリアル化したすべてのオブジェクトにnullが付いていることがわかりました メモリストリームを使用したときに発生せず、辞書の型として.Netオブジェクトを使用したときに発生しませんでした。 0-0 辞書:1-1 リスト:0 リスト:1 辞書:0 - ヌル 辞書:1- 以下は、私はそれが問題を示して作成したサンプルコードである このコードの出力は 辞書ヌル リスト:0Dictionary ToListシリアル化の問題

class Program 
{ 
    static void Main(string[] args) 
    { 
     A state = new A(); 

     Stream stream = File.Open("D:\\temp\\temp.txt", FileMode.Create); 
     BinaryFormatter bFormatter = new BinaryFormatter(); 
     bFormatter.Serialize(stream, state); 
     stream.Close(); 

     state.PrintData(); 

     stream = File.Open("D:\\temp\\temp.txt", FileMode.Open); 
     bFormatter = new BinaryFormatter(); 
     state = (A)bFormatter.Deserialize(stream); 
     stream.Close(); 

     state.PrintData(); 
    } 
} 

[Serializable()] 
public class A : ISerializable 
{ 
    Dictionary<int, B> dic = new Dictionary<int, B>(); 
    List<B> list = new List<B>(); 

    public A() 
    { 
     for (int i = 0; i < 4; i++) 
     { 
      dic.Add(i, new B(i)); 
      list.Add(new B(i)); 
     } 
    } 

    public void PrintData() 
    { 
     foreach (KeyValuePair<int, B> kvp in dic) 
     { 
      Console.WriteLine("Dictionary: " + kvp.Key.ToString() + "-" + ((kvp.Value != null) ? kvp.Value.ToString() : "Null")); 
     } 
     foreach(B b in list) 
     { 
      Console.WriteLine("List: " + b.ToString()); 
     } 
    } 

    public A(SerializationInfo info, StreamingContext context) 
    { 
     List<int> keys = info.GetValue("keys", typeof(List<int>)) as List<int>; 
     List<B> values = info.GetValue("values", typeof(List<B>)) as List<B>; 

     int count = keys.Count; 
     if(count == values.Count) 
     { 
      for(int i = 0; i < count; i++) 
      { 
       dic[keys[i]] = values[i]; 
      } 
     } 

     list = info.GetValue("list", typeof(List<B>)) as List<B>; 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue("keys", dic.Keys.ToList(), typeof(List<int>)); 
     info.AddValue("values", dic.Values.ToList(), typeof(List<B>)); 
     List<B> listFromDic = new List<B>(dic.Values.ToList()); 
     info.AddValue("list", listFromDic, typeof(List<B>)); 
    } 
} 

[Serializable()] 
public class B : ISerializable 
{ 
    int foo; 

    public B(int i) 
    { 
     foo = i; 
    } 

    public B(SerializationInfo info, StreamingContext context) 
    { 
     foo = info.GetInt32("foo"); 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue("foo", foo); 
    } 

    public override string ToString() 
    { 
     return (foo != null) ? foo.ToString() : String.Empty; 
    } 
} 

+0

なぜあなたはリストとして辞書をシリアライズしようとしていますか? 'Dictionary'は直接シリアライズ可能です。 – svick

+1

.NET4で辞書のシリアル化が変更され、古いシリアル化をサポートするための問題があります –

+0

こんにちは、Shimi、「.NET4では辞書のシリアル化が変更され、古いシリアル化をサポートするための問題があります」と強調したいですか? 。だから、他の視聴者はそれを知っているだろう。私は、ネット4の前方互換性が.net 2.0よりも良いと思った。 – findcaiyzh

答えて

2

辞書をシリアル化によってサポートされています。ここで私が修正したコードは動作します。

public A(SerializationInfo info, StreamingContext context) 
    { 
     dic = info.GetValue("mapping", typeof(Dictionary<int, B>)) as Dictionary<int, B>; 
     list = info.GetValue("list", typeof(List<B>)) as List<B>; 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue("mapping", dic, typeof(Dictionary<int, B>)); 
     List<B> listFromDic = new List<B>(dic.Values.ToList()); 
     info.AddValue("list", listFromDic, typeof(List<B>)); 
    } 



編集:言及 opはリストを使用する必要があります。次のように改訂コード。辞書dicは、コンストラクタpublic A(SerializationInfo info、StreamingContext context)で初期化できません。
理由:
オブジェクトの逆シリアル化の順序は保証されません。たとえば、あるタイプがまだデシリアライズされていないタイプを参照している場合、例外が発生します。このような依存関係を持つ型を作成する場合は、IDeserializationCallbackインターフェイスとOnDeserializationメソッドを実装することで問題を回避できます。 BがAのコンストラクタで作成されていないことを意味するISerializable Interface

:パラ上記

がから来ています。

改訂コード:

[Serializable()] 
public class A : ISerializable, IDeserializationCallback 
{ 
    Dictionary<int, B> dic = new Dictionary<int, B>(); 
    List<B> list = new List<B>(); 
    private List<int> keys = new List<int>(); 

    public A() 
    { 
     for (int i = 0; i < 4; i++) 
     { 
      dic.Add(i, new B(i)); 
      list.Add(new B(i)); 
     } 
    } 

    public void PrintData() 
    { 
     foreach (KeyValuePair<int, B> kvp in dic) 
     { 
      Console.WriteLine("Dictionary: " + kvp.Key.ToString() + "-" + ((kvp.Value != null) ? kvp.Value.ToString() : "Null")); 
     } 
     foreach (B b in list) 
     { 
      Console.WriteLine("List: " + b.ToString()); 
     } 
    } 

    public A(SerializationInfo info, StreamingContext context) 
    { 
     keys = info.GetValue("keys", typeof(List<int>)) as List<int>; 
     List<B> values = info.GetValue("values", typeof(List<B>)) as List<B>; 

     list = info.GetValue("list", typeof(List<B>)) as List<B>; 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue("keys", dic.Keys.ToList(), typeof(List<int>)); 
     info.AddValue("values", dic.Values.ToList(), typeof(List<B>)); 
     List<B> listFromDic = new List<B>(dic.Values.ToList()); 
     info.AddValue("list", listFromDic, typeof(List<B>)); 
    } 

    public void OnDeserialization(object sender) 
    { 
     dic = new Dictionary<int, B>(); 
     int count = keys.Count; 
     if (count == list.Count) 
     { 
      for (int i = 0; i < count; i++) 
      { 
       dic[keys[i]] = list[i]; 
      } 
     } 
    } 
} 
+0

+1、ニース。私のために働く。ところで、A()コンストラクタでコメントアウトされたコードを削除して、回答の質が向上します – sll

+0

辞書のシリアル化が.NET4で変更され、古いシリアル化をサポートするための問題があります –