CSharp · Console
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
// https://stackoverflow.com/questions/42794732/customized-serialization
public class Sprite
{
static int nextId = 0;
public Sprite()
{
this.runtimeId = Interlocked.Increment(ref nextId);
}
[NonSerialized]
readonly int runtimeId;
public int RuntimeId { get { return runtimeId; } }
public override string ToString()
{
return GetType().Name + ": " + RuntimeId.ToString();
}
public bool IsRegistered
{
get
{
foreach (var sprite in SpriteSurrogate.Sprites)
{
if (object.ReferenceEquals(this, sprite))
return true;
}
return false;
}
}
}
[Serializable]
class Displayable
{
public string name;
public Sprite icon;
}
class TestClass
{
public static void Test()
{
SpriteSurrogate.AddSprite("1", new Sprite());
SpriteSurrogate.AddSprite("2", new Sprite());
SpriteSurrogate.AddSprite("3", new Sprite());
SpriteSurrogate.AddSprite("4", new Sprite());
var root = SpriteSurrogate.Sprites.Select((s, i) => new Displayable { icon = s, name = "hello " + i.ToString() }).Concat(new [] { new Displayable { name = "empty" } }).ToList();
var selector = new SurrogateSelector();
var spriteSurrogate = new SpriteSurrogate();
spriteSurrogate.Register(selector);
BinaryFormatter binaryFormatter = new BinaryFormatter(selector, new StreamingContext());
var root2 = Copy(root, binaryFormatter);
Assert.IsTrue(root.Select(d => d.icon).SequenceEqual(root2.Select(d => d.icon)));
Console.WriteLine("{0} deserialized successfully. ", root2);
Console.WriteLine("Result: ");
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(root, Newtonsoft.Json.Formatting.Indented));
}
public static T Copy<T>(T original, BinaryFormatter binaryFormatter)
{
using (MemoryStream memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, original);
memoryStream.Seek(0, SeekOrigin.Begin);
return (T)binaryFormatter.Deserialize(memoryStream);
}
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
if (value == false)
throw new AssertionFailedException("failed");
}
}
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
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment.Version: {0}\n", Environment.Version);
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Exception thrown: ");
Console.WriteLine(ex);
throw;
}
}
}