[英]Customized Serialization
我有一些必須序列化的對象:
class Displayable{
string name;
Sprite icon;
}
icon
字段需要自定義序列化,因為Sprite
已被序列化(游戲引擎已將其序列化為不同的文件,格式不同),而我只需要存儲一種引用它們的方式(比如說string
,就是Dictionary<string, Sprite>
的鍵) Dictionary<string, Sprite>
)。
我使用BinaryFormatter
嘗試實現ISerializable
和ISerializationSurrogate
但是這兩種方法都在反序列化時創建了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
的某些問題,盡管在Unity3d中成功編譯,但它顯然仍無法在unity3d中 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.