簡體   English   中英

定制序列化

[英]Customized Serialization

我有一些必須序列化的對象:

class Displayable{
  string name;
  Sprite icon;
}

icon字段需要自定義序列化,因為Sprite已被序列化(游戲引擎已將其序列化為不同的文件,格式不同),而我只需要存儲一種引用它們的方式(比如說string ,就是Dictionary<string, Sprite>的鍵) Dictionary<string, Sprite> )。

我使用BinaryFormatter嘗試實現ISerializableISerializationSurrogate但是這兩種方法都在反序列化時創建了Sprite對象的新實例,因此它們不適合我的情況。 我想擁有ISerializationSurrogate相同的功能,除了我不希望SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)的第一個參數SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)因為我需要返回內存中已有的對象而不是接收解串器中的新實例,並用數據填充它。

我也嘗試了SharpSerializer之類的外部庫,但是我不喜歡使用公共無參數構造函數的約束,並且它實際上並不能讓您自定義特殊類的序列化。 我讀過有關ProtoBuffers的文章,但這不支持繼承,我需要在其他地方使用它。

所以我的要求是:

  • 繼承支持
  • 能夠為某些類型定義自定義序列化
  • 這些自定義類型的反序列化不應該自己創建實例

有圖書館這樣做嗎?

否則,我太挑剔了嗎? 通常如何實現對存儲在其他位置的對象的引用的序列化?

先感謝您。

編輯:這就是我想要的

public class SerializableSprite : ISerializationSurrogate
{
  public static Dictionary<string, Sprite> sprites;
  public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
    Sprite sprite = obj as Sprite;
    info.AddValue("spriteKey", sprite.name);
  }
  // The first parameter in this function is a newly instantiated Sprite, which I don't need
  public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) {
    return sprites[info.GetString("spriteKey")];
  }
}

為了防止BinaryFormatter在反序列化期間創建Sprite的新實例,在序列化期間,您可以調用SerializationInfo.SetType(Type)來指定要插入序列化流中的替代類型信息(通常是某些代理類型)。 在反序列SetObjectData()過程中, SetObjectData()將通過代理實例而不是“真實”類型進行初始化。 該代理類型必須依次實現IObjectReference以便最終可以將“真實”對象插入對象圖中,特別是通過在IObjectReference表中查找它。

以下是這樣做的:

class ObjectReferenceProxy<T> : IObjectReference
{
    public T RealObject { get; set; }

    #region IObjectReference Members

    object IObjectReference.GetRealObject(StreamingContext context)
    {
        return RealObject;
    }

    #endregion
}

public sealed class SpriteSurrogate : ObjectLookupSurrogate<string, Sprite>
{
    static Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
    static Dictionary<Sprite, string> spriteNames = new Dictionary<Sprite, string>();

    public static void AddSprite(string name, Sprite sprite)
    {
        if (name == null || sprite == null)
            throw new ArgumentNullException();
        sprites.Add(name, sprite);
        spriteNames.Add(sprite, name);
    }

    public static IEnumerable<Sprite> Sprites
    {
        get
        {
            return sprites.Values;
        }
    }

    protected override string GetId(Sprite realObject)
    {
        if (realObject == null)
            return null;
        return spriteNames[realObject];
    }

    protected override Sprite GetRealObject(string id)
    {
        if (id == null)
            return null;
        return sprites[id];
    }
}

public abstract class ObjectLookupSurrogate<TId, TRealObject> : ISerializationSurrogate where TRealObject : class
{
    public void Register(SurrogateSelector selector)
    {
        foreach (var type in Types)
            selector.AddSurrogate(type, new StreamingContext(StreamingContextStates.All), this);
    }

    IEnumerable<Type> Types
    {
        get
        {
            yield return typeof(TRealObject);
            yield return typeof(ObjectReferenceProxy<TRealObject>);
        }
    }

    protected abstract TId GetId(TRealObject realObject);

    protected abstract TRealObject GetRealObject(TId id);

    #region ISerializationSurrogate Members

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        var original = (TRealObject)obj;
        var id = GetId(original);
        info.AddValue("id", id);
        // use Info.SetType() to force the serializer to construct an object of type ObjectReferenceWrapper<TRealObject> during deserialization.
        info.SetType(typeof(ObjectReferenceProxy<TRealObject>));
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        // Having constructed an object of type ObjectReferenceWrapper<TRealObject>, 
        // look up the real sprite using the id in the serialization stream.
        var wrapper = (ObjectReferenceProxy<TRealObject>)obj;
        var id = (TId)info.GetValue("id", typeof(TId));
        wrapper.RealObject = GetRealObject(id);
        return wrapper;
    }

    #endregion
}

然后將其應用於BinaryFormatter ,如下所示:

        var selector = new SurrogateSelector();
        var spriteSurrogate = new SpriteSurrogate();
        spriteSurrogate.Register(selector);

        BinaryFormatter binaryFormatter = new BinaryFormatter(selector, new StreamingContext());

樣品提琴

更新資料

盡管以上代碼在.Net 3.5及更高版本中但由於IObjectReference的某些問題,盡管在成功編譯,但它顯然仍無法在 IObjectReference 以下內容在.Net 3.5及更高版本中也適用,並且通過從ISerializationSurrogate.SetObjectData()返回實際對象來避免使用IObjectReference 因此,它也應該在unity3d中工作(已在評論中確認):

public sealed class SpriteSurrogate : ObjectLookupSurrogate<string, Sprite>
{
    static Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
    static Dictionary<Sprite, string> spriteNames = new Dictionary<Sprite, string>();

    public static void AddSprite(string name, Sprite sprite)
    {
        if (name == null || sprite == null)
            throw new ArgumentNullException();
        sprites.Add(name, sprite);
        spriteNames.Add(sprite, name);
    }

    public static IEnumerable<Sprite> Sprites
    {
        get
        {
            return sprites.Values;
        }
    }

    protected override string GetId(Sprite realObject)
    {
        if (realObject == null)
            return null;
        return spriteNames[realObject];
    }

    protected override Sprite GetRealObject(string id)
    {
        if (id == null)
            return null;
        return sprites[id];
    }
}

public abstract class ObjectLookupSurrogate<TId, TRealObject> : ISerializationSurrogate where TRealObject : class
{
    class SurrogatePlaceholder
    {
    }

    public void Register(SurrogateSelector selector)
    {
        foreach (var type in Types)
            selector.AddSurrogate(type, new StreamingContext(StreamingContextStates.All), this);
    }

    IEnumerable<Type> Types
    {
        get
        {
            yield return typeof(TRealObject);
            yield return typeof(SurrogatePlaceholder);
        }
    }

    protected abstract TId GetId(TRealObject realObject);

    protected abstract TRealObject GetRealObject(TId id);

    #region ISerializationSurrogate Members

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        var original = (TRealObject)obj;
        var id = GetId(original);
        info.AddValue("id", id);
        // use Info.SetType() to force the serializer to construct an object of type SurrogatePlaceholder during deserialization.
        info.SetType(typeof(SurrogatePlaceholder));
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        // Having constructed an object of type SurrogatePlaceholder, 
        // look up the real sprite using the id in the serialization stream.
        var id = (TId)info.GetValue("id", typeof(TId));
        return GetRealObject(id);
    }

    #endregion
}

樣本小提琴2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM