questions/42794732/customized-serialization

CSharp · Console

/Program.cs

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");
        }
    }

    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
    }

					
	public class Program
	{
		public static void Main()
		{
			TestClass.Test();
		}
	}
;