gpt4 book ai didi

c# - 反序列化时字典为空

转载 作者:太空狗 更新时间:2023-10-29 22:58:43 25 4
gpt4 key购买 nike

我目前正在编写一个双向映射类,我在类的序列化/反序列化方面遇到了一些麻烦(底部的问题)。

这是类(class)中相关的部分。

/// <summary>
/// Represents a dictionary where both keys and values are unique, and the mapping between them is bidirectional.
/// </summary>
/// <typeparam name="TKey"> The type of the keys in the dictionary. </typeparam>
/// <typeparam name="TValue"> The type of the values in the dictionary. </typeparam>
[Serializable]
public class BidirectionalDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IEquatable<BidirectionalDictionary<TKey, TValue>>, ISerializable, IDeserializationCallback
{

/// <summary>
/// A dictionary that maps the keys to values.
/// </summary>
private readonly Dictionary<TKey, TValue> forwardMap;

/// <summary>
/// A dictionary that maps the values to keys.
/// </summary>
private readonly Dictionary<TValue, TKey> inverseMap;

/// <summary>
/// An instance of the dictionary where the values are the keys, and the keys are the values.
/// </summary>
private readonly BidirectionalDictionary<TValue, TKey> inverseInstance;

/// <summary>
/// Initializes a new instance of the dictionary class with serialized data. </summary>
/// </summary>
/// <param name="info"> The serialization info. </param>
/// <param name="context"> The sserialization context. </param>
protected BidirectionalDictionary(SerializationInfo info, StreamingContext context)
{
this.forwardMap = (Dictionary<TKey, TValue>)info.GetValue("UnderlyingDictionary", typeof(Dictionary<TKey, TValue>));
this.inverseMap = new Dictionary<TValue, TKey>(
forwardMap.Count,
(IEqualityComparer<TValue>)info.GetValue("InverseComparer", typeof(IEqualityComparer<TValue>)));

// forwardMap is always empty at this point.
foreach (KeyValuePair<TKey, TValue> entry in forwardMap)
inverseMap.Add(entry.Value, entry.Key);

this.inverseInstance = new BidirectionalDictionary<TValue, TKey>(this);
}

/// <summary>
/// Gets the data needed to serialize the dictionary.
/// </summary>
/// <param name="info"> The serialization info. </param>
/// <param name="context"> The serialization context. </param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("UnderlyingDictionary", forwardMap);
info.AddValue("InverseComparer", inverseMap.Comparer);
}
}

由于 forward- 和 inverseMap 字典包含完全相同的数据,我的想法是只序列化其中一个 (forwardMap),然后从反序列化数据构建另一个 (inverseMap)。但是,反序列化构造函数中的任何数据都不会填充 inverseMap。似乎只有在类的反序列化构造函数已经执行后,forwardMap 字典才会完全反序列化。

知道如何解决这个问题吗?

最佳答案

我假设您使用的是 BinaryFormatter .

BinaryFormatter是一个图形序列化器。对象不是存储在纯树中,而是分配临时对象 ID 并在遇到时存储。因此,当一个对象被反序列化时,不能保证所有引用的对象之前都已被反序列化。因此,您的 forwardMap 中的条目可能还没有填写。

正常的解决方法是添加 IDeserializationCallback 逻辑到你的类(class),并建立你的inverseMapinverseInstanceOnDeserialization 中的所有内容都被反序列化之后方法。但是, Dictionary<TKey, TValue> 还实现了 IDeserializationCallback ,这引入了一个额外的排序问题:不能保证它在你之前被调用。关于这个话题,Microsoft writes :

Objects are reconstructed from the inside out, and calling methods during deserialization can have undesirable side effects, since the methods called might refer to object references that have not been deserialized by the time the call is made. If the class being deserialized implements the IDeserializationCallback, the OnSerialization method will automatically be called when the entire object graph has been deserialized. At this point, all the child objects referenced have been fully restored. A hash table is a typical example of a class that is difficult to deserialize without using the event listener described above. It is easy to retrieve the key/value pairs during deserialization, but adding these objects back to the hash table can cause problems since there is no guarantee that classes that derived from the hash table have been deserialized. Calling methods on a hash table at this stage is therefore not advisable.

因此,您可以做几件事:

  1. 而不是存储 Dictionary<TKey,TValue> , 存储 KeyValuePair<TKey,TValue> 的数组.这具有使您的二进制数据更简单的优点,但确实需要您在 GetObjectData() 中分配数组。方法。

  2. 或遵循 dictionary reference source 中的建议:

    // It might be necessary to call OnDeserialization from a container if the container object also implements
    // OnDeserialization. However, remoting will call OnDeserialization again.
    // We can return immediately if this function is called twice.
    // Note we set remove the serialization info from the table at the end of this method.

    即在您的回调中,调用 OnDeserialization使用嵌套字典之前的方法:

    public partial class BidirectionalDictionary<TKey, TValue> : IDeserializationCallback
    {
    public void OnDeserialization(object sender)
    {
    this.forwardMap.OnDeserialization(sender);
    foreach (KeyValuePair<TKey, TValue> entry in forwardMap)
    {
    this.inverseMap.Add(entry.Value, entry.Key);
    }
    // inverseInstance will no longer be able to be read-only sicne it is being allocated in a post-deserialization callback.
    this.inverseInstance = new BidirectionalDictionary<TValue, TKey>(this);
    }

    (如果您愿意,可以使用 [OnDeserialied] 方法代替。)

顺便说一句,this blog post声称调用 OnDeserialization 是安全的HashTable 的方法来自包含类的反序列化构造函数,而不是稍后来自 OnDeserialization ,所以您可以尝试一下。

关于c# - 反序列化时字典为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25582842/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com