2014-08-30 22 views
5

Şu anda iki yönlü bir harita sınıfı yazıyorum ve sınıfın serileştirilmesi/serileştirilmesiyle ilgili bazı sorunlar yaşıyorum (altta soru).Sözlük, serileştirme üzerinde boş

İlgili sınıfın bölümleri aşağıdadır. ileri hem inverseMap sözlükleri yana

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

aynı verileri içerir, benim fikrim sadece bunlardan biri (forwardMap) seri hale ve sonra seri kaldırma üzerine 's verilerinden (inverseMap) diğer inşa etmekti. Ancak, inverseMap serileştirme yapıcısındaki herhangi bir veriyle doldurulmuyor. ForwardMap sözlüğünün, 'seriyi kaldırma kurucusu zaten yürütüldükten sonra yalnızca tamamen seri hale getirilmiş gibi görünüyor.

Bunu nasıl düzeltebileceğiniz hakkında bir fikriniz var mı?

+0

sadece onaylamak için ['BinaryFormatter'] kullanıyor musunuz (http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter%28v=vs.110% 29.aspx)? – dbc

+0

Kodun tamamını doğrudan test edebilmemiz için lütfen gönderebilir misiniz? –

+0

düzenlemek ve tam Posta koduna hakkında oldu, ama sorun @dbc aşağıda açıklanmıştır tam olarak ne olduğunu. Yani evet, BinaryFormatter kullanıyorum. – Henrik

cevap

7

BinaryFormatter kullanıyorsunuz.

BinaryFormatter bir grafik serializer yazılımıdır. Nesneler saf bir ağaçta depolanmaktan ziyade, geçici nesne kimlikleri atanır ve karşılaşıldıklarında saklanırlar. Böylece, bir nesne seri hale getirildiğinde, referans alınan tüm nesnelerin daha önce serileştirilmiş olduğu garanti edilmez. Böylece, forwardMap'unuzdaki girdiler henüz doldurulmamış olabilir.

Normal geçici çözüm sınıflarına IDeserializationCallback mantığı ekleyin, her şey OnDeserialization yönteminde serileştirilemezse olmuştur senin inverseMap ve inverseInstance sonra oluşturmaktır. Ancak, Dictionary<TKey, TValue>, ek bir sıralama problemi getiren IDeserializationCallback'u da uygulamaktadır: sizinkinden önce çağrılmış olması garanti edilemez. Bu konuyla ilgili Microsoft writes:

Nesneler içten dışa doğru yeniden vardır ve adı verilen yöntemler zamanında çağrı tarafından serisi kaldırılan edilmemiş başvurular itiraz atıfta bulunuyor olabilir çünkü seri kaldırma sırasında yöntemleri çağırmadan, istenmeyen yan etkileri olabilir yapılmış. Serileştirilmiş olan sınıf IDeserializationCallback'i uygularsa, nesne grafiğinin tamamı kaldırıldığında, OnSerialization yöntemi otomatik olarak çağrılır. Bu noktada, başvurulan tüm alt nesneler tamamen geri yüklendi. Bir karma tablosu, yukarıda açıklanan olay dinleyicisini kullanmadan serileştirilmesi zor olan bir sınıfın tipik bir örneğidir. Serileştirme sırasında anahtar/değer çiftlerini almak kolaydır, ancak bu nesneleri hash tablosuna eklemek problemlere neden olabilir çünkü hash tablosundan türetilen sınıfların serileştirilmediğine dair bir garanti yoktur. Bu aşamada hash tablosunda arama yöntemleri tavsiye edilmez.

  1. Aksine bir Dictionary<TKey,TValue> saklanmaz, KeyValuePair<TKey,TValue> dizisi depolamak:

Böylece yapabileceği birkaç şey vardır. Bu, ikili verilerinizi daha basit hale getirme avantajına sahiptir, ancak diziyi GetObjectData() yönteminize ayırmanızı gerektirir.

  • Ya dictionary reference source önerileri izleyin:

    // 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. 
    

    yanigeri arama, kullanmadan önce iç içe sözlük OnDeserialization yöntemini çağırın:

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

    (. Eğer tercih yerine eğer bir [OnDeserialied] yönteminde yapabileceğini)

  • arada, this blog post iddiaları o o OnDeserialization den sonra içeren sınıfın seri kaldırma yapıcısı bir HashTable ait OnDeserialization yöntemini çağırın ziyade güvenlidir, bu nedenle denemek için bir şans olabilir.

    +0

    Bu tam olarak sorunun sebebiydi. Aslında IDeserializationCallback yargıyı çalıştım ama belli ki (Sözlük da vardır kendi geri arama beri) çalışmadı. Şimdi hepsi mantıklı. – Henrik