2012-12-28 11 views
5

Bir Java oyununu C# (Puppy Games tarafından Titan Attacks) haline getiriyorum ve şimdi oyun görevinin serileştirilmesi olan son görevden başka bir şey yapmıyorum. dosyaları kaydetmek için..Net serileştirme - kalıtım ağacında özel [Serializable] ile karıştırma

Tipik hiyerarşi: Kaynak (taban) -> Özellik-> Ekran/Efekt/kişilik-> GameScreen/LaserEffect/İstilacı

Java kodu kullanan standart ObjectOutputStream/ObjectInputStream ikili seri gerçekleştirmek ancak rahatsız edici/bazı readResolve gerçekleştirir için serileştirme işlemini özelleştirmek için temel sınıf düzeyinde (Kaynak) writeResolve çalışması (bir kaynak isimlendirildiyse, seri hale getirilmez ve daha sonra bir hashmap kaynağını almak için kullanılan bir adla bir proxy döndürür).

Benim saf çözümler ben bütün bahisler inşa kapalı olduğundan eminim, körü körüne ...

public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { 
    if (name != null) { 
     // Got a name, so send a SerializedResource that just references us 
     info.AddValue("name", this.name); 
     info.SetType(typeof(SerializedResource)); 
     return; 
    } 

    //Serialize just MY fields (defined in Resource) 
    this.SerializeMyFields(info, context, typeof(Resource)); 
} 

Q bu yaklaşımı kopyalayıp TYPE geçersiz kılmak için temel sınıf içinde ISerializable uygulamaktır) Böylece - serileştirme ve serileştirme kurucusu ile birlikte miras zincirinin sonuna kadar ISerializable uygulamak zorundayım?

Not GetObjectData sanal olarak türetilmiş sınıflar, alanlarını serileştirebilir ve sonra temel sınıfı arayabilir. Bu çalışır ama bu LOTS sınıfı (100s) ekleyerek bir sıkıcı iştir. Bazı türetilmiş türler (Sprite, InvaderBehaviour, vb) ayrıca, daha da kötüsü yapmak için özel seri hale getirme işlemi de gerçekleştirir.

Jeffrey Richter'in konuyla ilgili makalelerine baktım ve bunun yerine bir ResourceSurrogateSelector: ISerializationSurrogate türü yapısını kullanmayı denedim, ancak bu serileştirme yöntemleri yalnızca serileştirilmekte olan tür bir Kaynaktır ve kaynaktan türeyen bir tür değilse çağrılır. Bir Invader ya da GameScreen'i serileştirme denenmez) Bunu yapmak için akıllıca bir yol var mı?

İki kod üssünü birbirine çok yakın tutmayı başardım ve bu dönüşümü çok daha kolay hale getirdi - Bu yaklaşımı burada (XmlSerializer, Protobuf, vb. gerçekten zorlayıcı bir sebep değil.

İşlemi otomatikleştirmek ve seri hale getirilebilen arabirimi uygulayan türleri yansıtacak ve tüm. Net serileştirme koduna sahip bir .cs dosyası oluşturabilmem için ana Java dosyalarını yazmadığım için Java yazmayı düşündüm (Kısmi yapıyorum)

PS - Hedef platformlar, bir şeylerin (yani sürüm 4) .Net tarafında ve muhtemelen PS Vita/belki iOS'u Mono kullanarak Windows8/Surface/XBox360 olacaktır. Kurtarılmaları, serileştirildikleri platformda serileştirilir.

DÜZENLEME bu yazı Sergey Teplyakov tarafından bir cevap .... .NET, C#: How to add a custom serialization attribute that acts as ISerializable interface ... istenilen türetilmiş sınıfları seçerek yardımcı olacak gibi görünüyor ISurrogateSelector arayüzüne beni yol açmıştır.

cevap

1

Şimdiye kadar gelmeyi başardığım şey budur ve onunla oldukça mutlu oldum :-) Sadece readResolve/writeReplace eklemek zorundayım ve işim bitti! (Büyük ihtimalle Object, SerializationInfo, StreamingContext, ObjectOutputStream'de iyi bir önlem almak için kaydırır).

using System; 
using System.Diagnostics; 
using System.IO; 
using System.Reflection; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 

using java.io; //My implementation of various Java classes 

namespace NewSerializationTest { 

public sealed class JavaSerializableSurrogateSelector : ISurrogateSelector 
{ 
    public void ChainSelector(ISurrogateSelector selector) { throw new NotImplementedException(); } 

    public ISurrogateSelector GetNextSelector() { throw new NotImplementedException(); } 

    public ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector) 
    { 
     if (typeof(Serializable).IsAssignableFrom(type)) 
     { 
      selector = this; 
      return new JavaSerializationSurrogate(); 
     } 

     //Type is not marked (java.io.)Serializable 
     selector = null; 
     return null; 
    } 
} 

public sealed class JavaSerializationSurrogate : ISerializationSurrogate { 

    //Method called to serialize a java.io.Serializable object 
    public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context) { 

     //Do the entire tree looking for the 'marker' methods 
     var type = obj.GetType(); 
     while (type != null) 
     { 
      var writeObject = type.GetMethod("writeObject", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext), typeof(Type) }, null); 
      if (writeObject != null) { 
       //Class has declared custom serialization so call through to that 
       writeObject.Invoke(obj, new object[] { info, context, type }); 
      } else { 
       //Default serialization of all non-transient fields at this level only (not the entire tree) 
       obj.SerializeFields(info, context, type); 
      } 

      type = type.BaseType; 
     } 
    } 

    //Method called to deserialize a java.io.Serializable object 
    public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { 

     //Do the entire tree looking for the 'marker' methods 
     var type = obj.GetType(); 
     while (type != null) 
     { 
      var readObject = type.GetMethod("readObject", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext), typeof(Type) }, null); 
      if (readObject != null) { 
       //Class has declared custom serialization so call through to that 
       readObject.Invoke(obj, new object[] { info, context, type }); 
      } else { 
       //Default serialization of all non-transient fields at this level only (not the entire tree) 
       obj.DeserializeFields(info, context, type); 
      } 

      type = type.BaseType; 
     } 

     return null; 
    } 
} 

[Serializable] 
class A : java.io.Serializable { 
    public string Field1; 
} 

[Serializable] 
class B : A { 
    public string Field2; 

    private void readObject(SerializationInfo stream, StreamingContext context, Type declaringType) { 
     stream.defaultReadObject(context, this, declaringType); 

     Debug.WriteLine("B: readObject"); 
    } 

    private void writeObject(SerializationInfo stream, StreamingContext context, Type declaringType) { 
     stream.defaultWriteObject(context, this, declaringType); 

     Debug.WriteLine("B: writeObject"); 
    } 
} 

[Serializable] 
class C: B { 
    public string Field3; 

    private void writeObject(SerializationInfo stream, StreamingContext context, Type declaringType) { 
     stream.defaultWriteObject(context, this, declaringType); 

     Debug.WriteLine("C: writeObject"); 
    } 
} 

public static class SerializationInfoExtensions { 

    public static void defaultWriteObject(this SerializationInfo info, StreamingContext context, object o, Type declaringType) { 
     o.SerializeFields(info, context, declaringType); 
    } 

    public static void defaultReadObject(this SerializationInfo info, StreamingContext context, object o, Type declaringType) { 
     o.DeserializeFields(info, context, declaringType); 
    } 
} 

class Program { 
    static void Main(string[] args) { 

     var myC = new C { Field1 = "tom", Field2 = "dick", Field3 = "harry" }; 

     using (var ms = new MemoryStream()) { 
      var binaryFormatter = new BinaryFormatter(); 
      binaryFormatter.SurrogateSelector = new JavaSerializableSurrogateSelector(); 

      binaryFormatter.Serialize(ms, myC); 
      ms.Position = 0; 
      var myCDeserialized = binaryFormatter.Deserialize(ms); 
     } 
    } 
} 

/// <summary> 
/// Extensions to the object class. 
/// </summary> 
public static class ObjectExtensions 
{ 
    /// <summary> 
    /// Serializes an object's class fields. 
    /// </summary> 
    /// <param name="source">The source object to serialize.</param> 
    /// <param name="info">SerializationInfo.</param> 
    /// <param name="context">StreamingContext.</param> 
    /// <param name="declaringType">The level in the inheritance whose fields are to be serialized - pass null to serialize the entire tree.</param> 
    public static void SerializeFields(this object source, SerializationInfo info, StreamingContext context, Type declaringType) 
    { 
     //Serialize the entire inheritance tree if there is no declaringType passed. 
     var serializeTree = declaringType == null; 

     //Set the level in the class heirarchy we are interested in - if there is no declaring type use the source type (and the entire tree will be done). 
     var targetType = declaringType ?? source.GetType(); 

     //Get the set of serializable members for the target type 
     var memberInfos = FormatterServices.GetSerializableMembers(targetType, context); 

     // Serialize the base class's fields to the info object 
     foreach (var mi in memberInfos) 
     { 
      if (serializeTree || mi.DeclaringType == targetType) { 
       //Specify the name to use as the key - if the entire tree is being done then the names will already have a prefix. Otherwise, we need to 
       //append the name of the declaring type. 
       var name = serializeTree ? mi.Name : mi.DeclaringType.Name + "$" + mi.Name; 

       info.AddValue(name, ((FieldInfo)mi).GetValue(source)); 
      } 
     } 
    } 

    /// <summary> 
    /// Deserializes an object's fields. 
    /// </summary> 
    /// <param name="source">The source object to serialize.</param> 
    /// <param name="info">SerializationInfo.</param> 
    /// <param name="context">StreamingContext.</param> 
    /// <param name="declaringType">The level in the inheritance whose fields are to be deserialized - pass null to deserialize the entire tree.</param> 
    public static void DeserializeFields(this object source, SerializationInfo info, StreamingContext context, Type declaringType) 
    { 
     //Deserialize the entire inheritance tree if there is no declaringType passed. 
     var deserializeTree = declaringType == null; 

     //Set the level in the class heirarchy we are interested in - if there is no declaring type use the source type (and the entire tree will be done). 
     var targetType = declaringType ?? source.GetType(); 

     var memberInfos = FormatterServices.GetSerializableMembers(targetType, context); 

     // Deserialize the base class's fields from the info object 
     foreach (var mi in memberInfos) 
     { 
      //Only serialize the fields at the specific level requested. 
      if (deserializeTree || mi.DeclaringType == declaringType) 
      { 
       // To ease coding, treat the member as a FieldInfo object 
       var fi = (FieldInfo) mi; 

       //Specify the name to use as the key - if the entire tree is being done then the names will already have a prefix. Otherwise, we need to 
       //append the name of the declaring type. 
       var name = deserializeTree ? mi.Name : mi.DeclaringType.Name + "$" + mi.Name; 

       // Set the field to the deserialized value 
       fi.SetValue(source, info.GetValue(name, fi.FieldType)); 
      } 
     } 
    } 
} 
} 
İlgili konular