6

Ben filestream içine uygulama verilerini seri hale getirmek için BinaryFormatter kullanılan bir eski uygulamayı çalışmak zorunda ana class özelliğiıserializable ve geriye dönük uyumluluk

ile işaretlendi herhangi optimizazion olmadan ("data.oldformat" adlı bir dosyada derler)
<serializable()>public MainClass 
....... 
end class 

ve ben sadece sınıf ıserializable arabirimini uygulayan yapılan seri/seri kaldırma işlemini optimize etmek bir girişimde seri kodu

dim b as new binaryformatter 
b.serialize(mystream,mymainclass) 

ve bazı optimize seriali yazdım kıymetleştirme optimizasyonu gerçekten iyi çalışıyor ama geriye dönük uyumluluk için eski dosyaları içinde veri reatrive için bir yol bulmak GEREKİR

<serializable()>public MainClass 
     implements ISerializable 
....... 
end class 

rutinleri.

Bunu nasıl yapabilirim?

Pierluigi

cevap

4

stmax ancak SerializationEntry.GetEnumerator() yerine try/catch kullandığı bu gibi uygulamak istiyorum, mükemmel bir cevabı vardır. Bu yol daha temiz ve daha hızlıdır.

public MainClass(SerializationInfo info, StreamingContext context) { 
    int version = 0; 
    foreach (SerializationEntry s in info) 
    { 
     if (s.Name == "version") 
     { 
      version = (int)s.Value; 
      break; 
     } 
    } 

    switch (version) { 
     case 0: 
     // deserialize "old format" 
     break; 
     case 1: 
     // deserialize "new format, version 1" 
     break; 
     default: 
     throw new NotSupportedException("version " + version + " is not supported."); 
    } 
} 

Ben .FirstOrDefault (kullanarak bir LINQ versiyonunu) tercih ediyorum, ama SerializationInfo IEnumerable uygulamıyor - karşısında, garip bir şekilde yeterli, hatta eski IEnumerable arabirimini uygulamaz.

0

Sadece şimdiye kadar yapıyorum aynı şeyi denemek

BinaryFormatter b = new BinaryFormatter(); 
MainClass a = b.DeSerialize(mystream) as MainClass; 

Uygulama ıserializable orijinal sınıf değişmedi, temelde sadece bazı yöntemler

+0

Gerekli seri oluşturucuyu (serializationInfo bilgisi, streamingContext içeriği) ekledim, böylece varsayılan sınıflandırma sırasında ana sınıfın kendi verilerini nasıl kaydettiğini bilmeden b.deserialize kullanamıyorum – pierusch

0

ekledik Nesnelerinizi serileştirirken ek bir Version alanı ekleyin (bu fazla yük eklememelidir). Daha sonra GetObjectData yönteminizde, önce sürüm alanını geri almayı deneyin ve bunun var olup olmadığını (SerializationException'ı yakalayarak) eski yolu veya yeni yolu yeniden seri hale getirin. Eski yol sadece tüm verileri serileştirmiş olacak, böylece her alan için Get ... öğesini arayabilmelisiniz.

+0

Bu, kullanılan seri hale getirme yordamı için uygundur getObjectData ama sorun özel bir kurucu (serializationinfo, serializationcontext olarak bağlam olarak) eski mainClass sürümü kullanmadı kullanarak seri hale getirme yordamı sırasında verileri almak için nasıl kullanılacağını bilmiyorum nesne – pierusch

0

Önceki kodunuz çalışmalıdır. Bir istisna var mı? yeni yapıcısı kullanmaya çalışın: Eğer geçirilen info-nesneyi kullanabilirsiniz

public MainClass(SerializationInfo info, StreamingContext context) {} 

: Zaten ISerializable arabirimi uyguladık beri

Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 
+0

Ben Had ... ama sınıf sadece seri hale getirilebilir olarak işaretlendiğinde binaryformatter veri kaydeder bilmek gerekiyor ... – pierusch

4

, muhtemelen de zaten gerekli yapıcı ekledik seri hale getirilmiş dosyadan veri almak için kurucuya. varsayılan olarak (yani, ISerializable uygulanmadığında), alan adları, serileştirme sırasında tanımlayıcılar olarak kullanılır. Eski sınıf bir alan olsaydı bu yüzden "int x" kullanarak bu serisini:

this.x = info.GetInt32("x"); 

yeni sürümler i normalde böyle, serileştirme sırasında bir "versiyonu" girişini ekleyin:

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

yazım hataları içerebilir,

public MainClass(SerializationInfo info, StreamingContext context) { 
    int version; 
    try { 
     version = info.GetInt32("version"); 
    } 
    catch { 
     version = 0; 
    } 

    switch (version) { 
     case 0: 
     // deserialize "old format" 
     break; 
     case 1: 
     // deserialize "new format, version 1" 
     break; 
     default: 
     throw new NotSupportedException("version " + version + " is not supported."); 
    } 
} 

ben bu kodu derlenmiş değil: seri kaldırma sırasında bu versiyon girişini kontrol etmek ve buna göre serisini.

yardımcı olacağını umuyorum.

+0

büyük cevap stmax! binaryformatter nesnesinin varsayılan davranışını nasıl buldunuz? – pierusch

+3

Varsayılan davranışıyla serileştirilmiş girişlerin "adlarını" bulmak için aşağıdakileri yaptım: foreach (info.GetEnumerator() içinde SerializationEntry girdisi) {Trace.WriteLine (entry.Name); } – stmax

+0

"version" alırken try/catch yerine, yerine SerializationInfo.GetEnumerator() kullanın ve "version" alanını arayın. Daha temizdir ve alan bulunamazsa istisnayı atmaktan kaçınmak, tüm serileştirmeyi (benim testimde) 2 kat daha hızlı hale getirir. SerializationInfo.Get() dahili olarak, aynı sayıdaki bir aramayı, bir numaralayıcı ile kendiniz yapıyormuş gibi kullanır ve bu sayede, alanların sayısında hem O (n) olur. –

İlgili konular