【问题标题】:Issues with Dictionary ToList serialization字典 ToList 序列化的问题
【发布时间】:2023-03-11 17:00:01
【问题描述】:

我尝试使用 ToList 选项序列化字典的值。 我发现在反序列化过程中,我序列化的所有对象都为 null 当我使用内存流时没有发生这种情况,当我使用 .Net 对象作为字典中的类型时也没有发生。 下面是我创建的显示问题的示例代码 这段代码的输出是 字典:0-0 字典:1-1 列表:0 清单:1 字典:0-空 字典:1-空 列表:0

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;
    }
}

【问题讨论】:

  • 您为什么要尝试将字典序列化为列表? Dictionary 可直接序列化。
  • 因为 .NET4 中的字典序列化已更改,支持旧序列化存在问题
  • 嗨,Shimi,您想在问题中突出显示“.NET4 中的字典序列化已更改,支持旧序列化存在问题”。所以其他观众会知道这一点。我认为 .net 4 的前向兼容性优于 .net 2.0
  • 嗨序列化的问题不是前向兼容性,而是向后兼容性,如果你在.Net4中序列化字典,你不能在以前的.Net中反序列化它,据我了解这是因为他们添加了内部比较器。解决方案也在我的代码中。但我不确定它为什么会发生,我认为这是因为 ToList 的输出不可序列化但我不确定

标签: c# generics serialization dictionary


【解决方案1】:

序列化支持字典。这是我修改的代码。

    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>));
    }



编辑: 提到的操作必须使用列表。修改后的代码如下。字典 dic 无法在构造函数 public A(SerializationInfo info, StreamingContext context) 中初始化。
因为:
无法保证对象反序列化的顺序。例如,如果一个类型引用了一个尚未反序列化的类型,则会发生异常。如果您正在创建具有此类依赖关系的类型,则可以通过实现 IDeserializationCallback 接口和 OnDeserialization 方法来解决此问题。

以上段落来自:ISerializable Interface

这意味着 B 不是在 A 的构造函数中创建的。

修改代码:

[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];
            }
        }
    }
}

【讨论】:

  • +1,很好。为我工作。顺便说一句,删除 A() 构造函数中注释掉的代码,这样答案的质量会更好
  • 我没有使用字典序列化,因为字典序列化在 .NET4 中发生了变化,支持旧的序列化存在问题
猜你喜欢
  • 1970-01-01
  • 2011-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多