Beispiel #1
0
        public byte[] ToGlbBytes(SerializerTypes serializer = SerializerTypes.UniJSON)
        {
            string json;

            if (serializer == SerializerTypes.UniJSON)
            {
                var c = new JsonSchemaValidationContext(this)
                {
                    EnableDiagnosisForNotRequiredFields = true,
                };
                json = JsonSchema.FromType(GetType()).Serialize(this, c);
            }
            else if (serializer == SerializerTypes.Generated)
            {
                var f = new JsonFormatter();
                f.GenSerialize(this);
                json = f.ToString().ParseAsJson().ToString("  ");
            }
            else if (serializer == SerializerTypes.JsonSerializable)
            {
                // Obsolete
                json = ToJson();
            }
            else
            {
                throw new Exception("[UniVRM Export Error] unknown serializer type");
            }

            RemoveUnusedExtensions(json);

            return(Glb.ToBytes(json, buffers[0].GetBytes()));
        }
Beispiel #2
0
        public static void Serialize(object instance, out string xmlContent, out string serializerType)
        {
            SerializerTypes serializerTypeValue = SerializerTypes.Primitive;

            xmlContent = string.Empty;
            Type instanceType = typeof(object);

            if (instance != null)
            {
                if (instanceType.IsPrimitive || instanceType == typeof(string))
                {
                    xmlContent = string.Format("<{0}>{1}</{0}>", instanceType.Name, instance);
                }
                else if (instanceType.GetCustomAttributes(typeof(SerializableAttribute), true).FirstOrDefault() != null)
                {
                    serializerTypeValue = SerializerTypes.XmlSerializer;
                    StringWriter sww    = new StringWriter();
                    XmlWriter    writer = XmlWriter.Create(sww);
                    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(instanceType);
                    serializer.Serialize(sww, instanceType);
                    xmlContent = sww.ToString();
                }
                else
                {
                    serializerTypeValue = SerializerTypes.XmlObjectSerializer;
                    XmlObjectSerializer serializer = new XmlObjectSerializer();
                    xmlContent = serializer.Serialize(instance, instanceType).OuterXml;
                }
            }

            serializerType = string.Format(SerializerTypeFormat, serializerTypeValue, instanceType.AssemblyQualifiedName);
        }
Beispiel #3
0
        /// <summary>
        /// Retrieves a setting from storage.
        /// </summary>
        /// <typeparam name="T">Type of the stored value.</typeparam>
        /// <param name="key">Unique key for the setting.</param>
        /// <param name="location">Location the setting should be retrieved from.</param>
        /// <param name="serializerType">How the setting should be serialized to storage.</param>
        /// <returns>Awaitable task is returned.</returns>
        public T LoadSetting <T>(string key, ApplicationDataContainer container, SerializerTypes serializerType = SerializerTypes.Default)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                throw new ArgumentNullException(nameof(key));
            }

            try
            {
                if (container.Values.ContainsKey(key))
                {
                    // Don't deserialize the value if its a primitive type
                    if (TypeUtility.IsPrimitive(typeof(T)))
                    {
                        return((T)container.Values[key]);
                    }
                    else
                    {
                        return(Serializer.Deserialize <T>(container.Values[key].ToString(), serializerType));
                    }
                }
                else
                {
                    return(default(T)); // Not found in the container return the default value.
                }
            }
            catch (Exception ex)
            {
                Platform.Current.Logger.LogError(ex, "Error retrieving key '{0}' from container '{1}' using '{2}' serializer.", key, container.Locality, serializerType);
                return(default(T));
            }
        }
            public static T Read(Stream stream, T instance, int version)
            {
                var minSupportedVersion = SerializerTypes.GetMinSupported(Type);

                if (version < minSupportedVersion)
                {
                    throw new InvalidDataException($"Received version less than minimum supported ({ version } < { minSupportedVersion })");
                }

                var boxedInstance = (object)instance;

                while (true)
                {
                    var token = stream.ReadString();
                    if (token == SerializerTypes.TypeEndToken)
                    {
                        break;
                    }

                    if (!FieldsMap.TryGetValue(token, out BinField binField))
                    {
                        continue;
                    }

                    var value = BinSerializer <object> .Deserialize(stream);

                    binField.SetValue(boxedInstance, value);
                }

                return((T)boxedInstance);
            }
        public static IImageSerializer Get(SerializerTypes serializerTypes)
        {
            switch (serializerTypes)
            {
                case SerializerTypes.BasicSerializer:
                    return new BasicImageSerializer();
            }

            return new DefaultImageSerializer();
        }
Beispiel #6
0
        public static IImageSerializer Get(SerializerTypes serializerTypes)
        {
            switch (serializerTypes)
            {
            case SerializerTypes.BasicSerializer:
                return(new BasicImageSerializer());
            }

            return(new DefaultImageSerializer());
        }
Beispiel #7
0
        public void TestManual()
        {
            SerializerTypes.AddType(
                new BinTypeDescription(typeof(Manual), "Manual")
                , new BinTypeVersion(10, 0)
                , BinTypeProcess.Create <Manual>(Manual.Write, Manual.Read)
                );

            var input = new Manual();

            input.FieldOne = "asd";
            input.FieldTwo = "lsd";

            var output = SerializeDeserialize(input);

            Assert.AreEqual(input.FieldOne, output.FieldOne);
            Assert.AreEqual(input.FieldTwo, output.FieldTwo);
        }
Beispiel #8
0
        public void CallbacksManualTest()
        {
            SerializerTypes.AddType(
                new BinTypeDescription(typeof(CallbacksTestManualType), "CallbacksTestManualType")
                , new BinTypeVersion(42, 0)
                , BinTypeProcess.Create <CallbacksTestManualType>(CallbacksTestManualType.Write, CallbacksTestManualType.Read)
                );

            var instance = new CallbacksTestManualType();

            instance.First = 10;

            var result = SerializeDeserialize(instance);

            Assert.AreEqual(result.First, 10);
            Assert.AreEqual(result.Second, 10);
            Assert.AreEqual(result.FromFirstAndSecond, 100);
        }
Beispiel #9
0
        /// <summary>
        /// Deserializes a string back into an instance of an object.
        /// </summary>
        /// <typeparam name="T">Type of the object to be returned.</typeparam>
        /// <param name="data">String data to be deserialized.</param>
        /// <param name="serializerType">Use the default serializer or specific a particular serializer.</param>
        /// <returns>Object instance from the deserialized data string.</returns>
        public static T Deserialize <T>(string data, SerializerTypes serializerType = SerializerTypes.Default)
        {
            if (serializerType == SerializerTypes.Default)
            {
                serializerType = DefaultSerializerType;
            }

            switch (serializerType)
            {
            case SerializerTypes.Xml:
                return(DeserializeFromXml <T>(data));

            case SerializerTypes.Json:
                return(DeserializeFromJson <T>(data));

            default:
                throw new NotSupportedException("Unrecognized file type " + serializerType);
            }
        }
Beispiel #10
0
        /// <summary>
        /// Serialize an object to string.
        /// </summary>
        /// <param name="obj">Object to serialize.</param>
        /// <param name="serializerType">Use the default serializer or specific a particular serializer.</param>
        /// <returns>String returned from the serializer.</returns>
        public static string Serialize(object obj, SerializerTypes serializerType = SerializerTypes.Default)
        {
            if (serializerType == SerializerTypes.Default)
            {
                serializerType = DefaultSerializerType;
            }

            switch (serializerType)
            {
            case SerializerTypes.Xml:
                return(SerializeToXml(obj));

            case SerializerTypes.Json:
                return(SerializeToJson(obj));

            default:
                throw new NotImplementedException("Unrecognized file type " + serializerType);
            }
        }
Beispiel #11
0
        public void TestManualGeneric()
        {
            var write = typeof(SerializeTests).GetMethod("WriteManualGeneric", BindingFlags.Static | BindingFlags.Public);
            var read  = typeof(SerializeTests).GetMethod("ReadManualGeneric", BindingFlags.Static | BindingFlags.Public);

            SerializerTypes.AddType(
                new BinTypeDescription(typeof(ManualGenericType <,>), "ManualGenericType")
                , new BinTypeVersion(10, 0)
                , BinTypeProcess.Create(write, read)
                );

            var input = new ManualGenericType <string, string>();

            input.FieldOne = "asd";
            input.FieldTwo = "lsd";

            var output = SerializeDeserialize(input);

            Assert.AreEqual(input.FieldOne, output.FieldOne);
            Assert.AreEqual(input.FieldTwo, output.FieldTwo);
        }
Beispiel #12
0
        private static void GetSerializerDetails(string serializerType, out SerializerTypes serializerTypeValue,
                                                 out Type serializedType)
        {
            serializerTypeValue = default(SerializerTypes);
            serializedType      = default(Type);

            int    index = serializerType.IndexOf(".");
            string serializerTypeValueString = serializerType.Substring(0, serializerType.IndexOf("."));
            string serializedTypeName        = serializerType.Substring(index + 1);

            if (SerializationHelper.PrimitiveTypes.Contains(serializedTypeName))
            {
                serializedType      = SerializationHelper.PrimitiveTypes[serializedTypeName];
                serializerTypeValue = SerializerTypes.Primitive;
                return;
            }
            else if (serializedTypeName.IsAny(StringComparison.OrdinalIgnoreCase, "int", "string", "double", "float", "long"))
            {
                serializedType      = Type.GetType(serializedTypeName);
                serializerTypeValue = (SerializerTypes)Enum.Parse(typeof(SerializerTypes), serializerTypeValueString);
            }
        }
Beispiel #13
0
        /// <summary>
        /// Gets data from the specified URL.
        /// </summary>
        /// <typeparam name="T">Type for the strongly typed class representing data returned from the URL.</typeparam>
        /// <param name="url">URL to retrieve data from.</param>
        /// <param name="serializerType">Specifies how the data should be deserialized.</param>
        /// <param name="retryCount">Number of retry attempts if a call fails. Default is zero.</param>
        /// <returns>Instance of the type specified representing the data returned from the URL.</returns>
        /// <summary>
        protected async Task <T> GetAsync <T>(string url, CancellationToken?ct = null, SerializerTypes serializerType = SerializerTypes.Default)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException(nameof(url));
            }

            var response = await this.Client.GetAsync(new Uri(this.BaseUri, url)).AsTask(ct.HasValue ? ct.Value : CancellationToken.None);

            this.Log(response);
            response.EnsureSuccessStatusCode();
            var data = await response.Content.ReadAsStringAsync();

            return(Serializer.Deserialize <T>(data, serializerType));
        }
        private static void GetSerializerDetails(string serializerType, out SerializerTypes serializerTypeValue,
                                                 out Type serializedType)
        {
            serializerTypeValue = default(SerializerTypes);
            serializedType = default(Type);

            int index = serializerType.IndexOf(".");
            string serializerTypeValueString = serializerType.Substring(0, serializerType.IndexOf("."));
            string serializedTypeName = serializerType.Substring(index + 1);

            if (SerializationHelper.PrimitiveTypes.Contains(serializedTypeName))
            {
                serializedType = SerializationHelper.PrimitiveTypes[serializedTypeName];
                serializerTypeValue = SerializerTypes.Primitive;
                return;
            }
            else if (serializedTypeName.IsAny(StringComparison.OrdinalIgnoreCase, "int", "string", "double", "float", "long"))
            {

                serializedType = Type.GetType(serializedTypeName);
                serializerTypeValue = (SerializerTypes) Enum.Parse(typeof(SerializerTypes), serializerTypeValueString);
            }
        }
Beispiel #15
0
        /// <summary>
        /// Saves a string to file in storage.
        /// </summary>
        /// <param name="path">Path and name of the file.</param>
        /// <param name="data">Data to write to file.</param>
        /// <param name="location">Location to store the file.</param>
        /// <returns>Awaitable task returning the final file path in storage.</returns>
        public async Task <StorageFile> SaveFileAsync(string path, object data, StorageFolder folder, SerializerTypes serializerType = SerializerTypes.Default)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentNullException(nameof(path));
            }

            // Serialize the object to string
            string dataAsString = null;

            if (data is string)
            {
                dataAsString = data.ToString();
            }
            else if (data != null)
            {
                dataAsString = Serializer.Serialize(data, serializerType);
            }

            if (string.IsNullOrEmpty(dataAsString))
            {
                // Delete the file if null or empty string.
                await this.DeleteFileAsync(path, folder);

                return(null);
            }
            else
            {
                // Get to the requested folder destination in the path.
                StorageFolder destinationFolder = await this.GetToFolderFromPathAsync(path, folder, true);

                // Create the file
                StorageFile textFile = await destinationFolder.CreateFileAsync(Path.GetFileName(path), CreationCollisionOption.ReplaceExisting);

                // Write string data to file.
                using (IRandomAccessStream textStream = await textFile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    using (DataWriter textWriter = new DataWriter(textStream))
                    {
                        textWriter.WriteString(dataAsString);
                        await textWriter.StoreAsync();
                    }
                }

                // Return handle to file
                return(textFile);
            }
        }
Beispiel #16
0
        /// <summary>
        /// Loads a file from storage.
        /// </summary>
        /// <typeparam name="T">Type representing the data stored.</typeparam>
        /// <param name="path">Path and name of the file.</param>
        /// <param name="folder">Which storage location to retrieve the file from.</param>
        /// <returns>String contents from the file or null if it doesn't exists.</returns>
        /// <returns>Awaitable task of type specified.</returns>
        public async Task <T> LoadFileAsync <T>(string path, StorageFolder folder, SerializerTypes fileType = SerializerTypes.Default)
        {
            string data = await this.ReadFileAsStringAsync(path, folder);

            return(Serializer.Deserialize <T>(data, fileType));
        }
Beispiel #17
0
        /// <summary>
        /// Saves a setting to storage.
        /// </summary>
        /// <param name="key">Unique key for the setting.</param>
        /// <param name="obj">Value to store.</param>
        /// <param name="location">Location the setting should be stored to.</param>
        /// <param name="serializerType">How the setting should be deserialized from storage.</param>
        public void SaveSetting(string key, object obj, ApplicationDataContainer container, SerializerTypes serializerType = SerializerTypes.Default)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                throw new ArgumentNullException(nameof(key));
            }

            // Remove the value if null
            if (obj == null)
            {
                if (container.Values.ContainsKey(key))
                {
                    container.Values.Remove(key);
                }
                return;
            }

            // Don't serialize the object if its a primitive type.
            object value = null;

            if (TypeUtility.IsPrimitive(obj.GetType()))
            {
                value = obj;
            }
            else
            {
                value = Serializer.Serialize(obj, serializerType);
            }

            // Update or add the setting.
            if (container.Values.ContainsKey(key))
            {
                container.Values[key] = value;
            }
            else
            {
                container.Values.Add(key, value);
            }
        }
Beispiel #18
0
 /// <summary>
 /// Saves a setting to the LocalSettings container.
 /// </summary>
 /// <param name="key">Unique key for the setting.</param>
 /// <param name="obj">Object to store in the LocalSettings container.</param>
 /// <param name="serializerType">How the setting should be serialized to storage.</param>
 public void SaveSetting(string key, object obj, SerializerTypes serializerType = SerializerTypes.Default)
 {
     this.SaveSetting(key, obj, ApplicationData.Current.LocalSettings, serializerType);
 }
Beispiel #19
0
 public SerializerTypeAttribute(string projectHomeUrl, SerializerTypes serializerTypeDescription)
 {
     ProjectHomeUrl            = projectHomeUrl;
     SerializerTypeDescription = serializerTypeDescription;
 }
Beispiel #20
0
 /// <summary>
 /// Loads a setting from storage.
 /// </summary>
 /// <typeparam name="T">Type of the object stored in settings.</typeparam>
 /// <param name="key">Unique key for the setting.</param>
 /// <param name="serializerType">How the setting should be serialized to storage.</param>
 /// <returns>Object instance of the type specified if found else null.</returns>
 public T LoadSetting <T>(string key, SerializerTypes serializerType = SerializerTypes.Default)
 {
     return(this.LoadSetting <T>(key, ApplicationData.Current.LocalSettings, serializerType));
 }
        private static void GenerateArrayWriter(ILGenerator il, TypeImpl type)
        {
            var elementType = type.TypeInfo.GetElementType();

            var getRefId = typeof(RefWriterWatcher)
                           .GetTypeInfo()
                           .GetMethod(nameof(RefWriterWatcher.GetRefId), BindingFlags.Public | BindingFlags.Static);

            var getLowerBound = typeof(Array)
                                .GetTypeInfo()
                                .GetMethod(nameof(Array.GetLowerBound), BindingFlags.Instance | BindingFlags.Public);

            var serialize = typeof(BinSerializer <>)
                            .MakeGenericType(elementType)
                            .GetTypeInfo()
                            .GetMethod(nameof(BinSerializer <object> .Serialize), BindingFlags.Static | BindingFlags.Public);

            il.DeclareLocal(typeof(int));  // Array length
            il.DeclareLocal(typeof(int));  // Array index
            il.DeclareLocal(typeof(bool)); // Ref id created flag

            var skipLabel     = il.DefineLabel();
            var zeroBased     = il.DefineLabel();
            var loopLabel     = il.DefineLabel();
            var exitLoopLabel = il.DefineLabel();

            BSDebug.TraceStart(il, "Write " + type.TypeInfo.Name);

            // Write type
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, SerializerTypes.GetTypeId(type));
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(string)));

            // Write refId
            il.Emit(OpCodes.Ldarg_0);           // Load stream
            il.Emit(OpCodes.Ldarg_1);           // Load obj
            il.Emit(OpCodes.Ldloca_S, (byte)2); // Load address of bool local
            il.Emit(OpCodes.Call, getRefId);    // Obj => RefId
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(int)));

            // Check case when reference type already serialized.
            // If null be returned then created flag be zero too and serialization will be skipped.
            il.Emit(OpCodes.Ldloc_2);
            il.Emit(OpCodes.Brfalse, skipLabel);

            var dim = type.TypeInfo.GetArrayRank();

            if (dim == 1)
            {
                // Dimension check
                il.Emit(OpCodes.Ldarg_1);                 // Load array
                il.Emit(OpCodes.Ldc_I4_0);                // Load zero (0 dim)
                il.Emit(OpCodes.Callvirt, getLowerBound); // Get lower bound of 0 dim
                il.Emit(OpCodes.Brfalse, zeroBased);      // If result 0 then jump to zeroBased

                // Throw exception if non zero based
                il.Emit(OpCodes.Ldstr, "Non zero based arrays not supported.");
                il.Emit(OpCodes.Newobj, typeof(InvalidOperationException).GetTypeInfo().GetConstructor(new[] { typeof(string) }));
                il.Emit(OpCodes.Throw);

                // Write array length
                il.MarkLabel(zeroBased);
                il.Emit(OpCodes.Ldarg_0); // Load stream
                il.Emit(OpCodes.Ldarg_1); // Load array
                il.Emit(OpCodes.Ldlen);   // Load array length
                il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(int)));

                // Set array length
                il.Emit(OpCodes.Ldarg_1); // Load array
                il.Emit(OpCodes.Ldlen);   // Load array length
                il.Emit(OpCodes.Stloc_0); // Set to 0 local

                // Set array index to 0
                il.Emit(OpCodes.Ldc_I4_0); // Load 0
                il.Emit(OpCodes.Stloc_1);  // Set to 1 local

                // Loop start
                il.MarkLabel(loopLabel);

                // Loop check
                il.Emit(OpCodes.Ldloc_0);            // Load array length
                il.Emit(OpCodes.Ldloc_1);            // Load current index
                il.Emit(OpCodes.Beq, exitLoopLabel); // If equals then exit

                // Write element to stream
                il.Emit(OpCodes.Ldarg_0);             // Load stream
                il.Emit(OpCodes.Ldarg_1);             // Load array
                il.Emit(OpCodes.Ldloc_1);             // Load current index
                il.Emit(OpCodes.Ldelem, elementType); // Load element
                il.Emit(OpCodes.Call, serialize);

                // Inrement
                il.Emit(OpCodes.Ldloc_1);  // Load current index
                il.Emit(OpCodes.Ldc_I4_1); // Load 1
                il.Emit(OpCodes.Add);      // Add
                il.Emit(OpCodes.Stloc_1);  // Set current index

                // Jump to loop start
                il.Emit(OpCodes.Br, loopLabel);
            }
            else
            {
                throw new NotSupportedException("Arrays with non single dimension not supported.");
            }

            // Skipped
            il.MarkLabel(skipLabel);
            il.MarkLabel(exitLoopLabel);

            BSDebug.TraceEnd(il, "Write " + type.TypeInfo.FullName);

            // End
            il.Emit(OpCodes.Ret);
        }
        private static void GenerateObjectReader(ILGenerator il, TypeImpl type)
        {
            var addRef = typeof(RefReaderWatcher)
                         .GetTypeInfo()
                         .GetMethod(nameof(RefReaderWatcher.AddRef), BindingFlags.Public | BindingFlags.Static)
                         .MakeGenericMethod(type.Type);

            var tryGetRef = typeof(RefReaderWatcher)
                            .GetTypeInfo()
                            .GetMethod(nameof(RefReaderWatcher.TryGetRef), BindingFlags.Public | BindingFlags.Static)
                            .MakeGenericMethod(type.Type);

            var getTypeFromHandle = typeof(Type)
                                    .GetTypeInfo()
                                    .GetMethod(nameof(Type.GetTypeFromHandle), BindingFlags.Public | BindingFlags.Static);

            var defaultCtor = type.TypeInfo.GetConstructor(Type.EmptyTypes);

            var getUninitializedObject = typeof(FormatterServices)
                                         .GetTypeInfo()
                                         .GetMethod(nameof(FormatterServices.GetUninitializedObject), BindingFlags.Public | BindingFlags.Static);

            var dynamicObjectRead = typeof(DynamicObjectReader <>)
                                    .MakeGenericType(type.Type)
                                    .GetTypeInfo()
                                    .GetMethod(nameof(DynamicObjectReader <object> .Read), BindingFlags.Public | BindingFlags.Static);

            var stringEquals = typeof(string)
                               .GetTypeInfo()
                               .GetMethod(nameof(string.Equals), new[] { typeof(string), typeof(string), typeof(StringComparison) });

            var onDeserialized = typeof(IBinSerializable).GetMethod(nameof(IBinSerializable.OnDeserialized));


            il.DeclareLocal(typeof(int));                 // ref if
            il.DeclareLocal(type.Type);                   // readed object
            il.DeclareLocal(typeof(string));              // last readed field id
            il.DeclareLocal(typeof(int));                 // readed object version
            il.DeclareLocal(typeof(DeserializationInfo)); // info

            var resultLabel   = il.DefineLabel();
            var readFastLabel = il.DefineLabel();

            // Process reference id
            if (!type.TypeInfo.IsValueType)
            {
                var tryLoadReferenceLabel = il.DefineLabel();

                // Read reference id
                il.Emit(OpCodes.Ldarg_0);                                               // Load stream
                il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamReader(typeof(int))); // Read ref id
                il.Emit(OpCodes.Dup);                                                   // Duplicate ref id
                il.Emit(OpCodes.Stloc_0);                                               // Set ref id to local

                // Check if result null
                il.Emit(OpCodes.Brtrue, tryLoadReferenceLabel); // Check if null was written

                // Null was written (return null)
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Stloc_1);         // Set result to null
                il.Emit(OpCodes.Br, resultLabel); // Jump to result

                // Try get readed reference
                il.MarkLabel(tryLoadReferenceLabel);
                il.Emit(OpCodes.Ldloc_0);             // Load reference id
                il.Emit(OpCodes.Ldloca_S, (byte)1);   // Load address of result
                il.Emit(OpCodes.Call, tryGetRef);
                il.Emit(OpCodes.Brtrue, resultLabel); // Jump to result if reference already exist
            }

            // Read version
            il.Emit(OpCodes.Ldarg_0);                                               // Load stream
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamReader(typeof(int))); // Read saved version
            il.Emit(OpCodes.Stloc_3);                                               // Save version to local

            var reader = SerializerTypes.TryGetStreamReader(type);

            if (reader != null)
            {
                // Read
                il.Emit(OpCodes.Ldarg_0); // Load stream
                il.Emit(OpCodes.Call, reader);
                il.Emit(OpCodes.Stloc_1); // Set result to local

                // Add reference to watcher
                if (!type.TypeInfo.IsValueType)
                {
                    il.Emit(OpCodes.Ldloc_0); // Load reference id
                    il.Emit(OpCodes.Ldloc_1); // Load result object reference
                    il.Emit(OpCodes.Call, addRef);
                }
            }
            else
            {
                // Create
                if (!type.TypeInfo.IsValueType)
                {
                    if (defaultCtor != null)
                    {
                        il.Emit(OpCodes.Newobj, defaultCtor);
                        il.Emit(OpCodes.Stloc_1); // Set result to local
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldtoken, type.Type);
                        il.Emit(OpCodes.Call, getTypeFromHandle);
                        il.Emit(OpCodes.Call, getUninitializedObject);
                        il.Emit(OpCodes.Castclass, type.Type);
                        il.Emit(OpCodes.Stloc_1); // Set result to local
                    }
                }
                else
                {
                    il.Emit(OpCodes.Ldloca_S, (byte)1); // Load result local address
                    il.Emit(OpCodes.Initobj, type.Type);
                }

                // Add reference to watcher
                if (!type.TypeInfo.IsValueType)
                {
                    il.Emit(OpCodes.Ldloc_0); // Load reference id
                    il.Emit(OpCodes.Ldloc_1); // Load result object reference
                    il.Emit(OpCodes.Call, addRef);
                }

                // Read code type version
                var version = SerializerTypes.GetVersion(type);

                il.Emit(OpCodes.Ldloc_3);         // Load version
                il.Emit(OpCodes.Ldc_I4, version); // Load program type version
                il.Emit(OpCodes.Beq, readFastLabel);

                // Call dynamic read if versions not equal
                il.Emit(OpCodes.Ldarg_0);                 // Load stream
                il.Emit(OpCodes.Ldloc_1);                 // Load obj instance
                il.Emit(OpCodes.Ldloc_3);                 // Load version
                il.Emit(OpCodes.Call, dynamicObjectRead); // Do dynamic read
                il.Emit(OpCodes.Stloc_1);                 // Set readed value to result local
                il.Emit(OpCodes.Br, resultLabel);         // Jump to return code part

                il.MarkLabel(readFastLabel);

                // Read
                var typeReader = SerializerTypes.TryGetTypeReader(type);
                if (typeReader != null)
                {
                    // Read type
                    il.Emit(OpCodes.Ldarg_0); // Load stream
                    il.Emit(OpCodes.Ldloc_1); // Load obj instance
                    il.Emit(OpCodes.Ldloc_3); // Load version
                    il.Emit(OpCodes.Call, typeReader);
                    il.Emit(OpCodes.Stloc_1); // Set result to local
                }
                else
                {
                    // Read fields
                    Label?nextFieldLabel = null;

                    foreach (var binField in BinField.Get(type.Type))
                    {
                        var markCurrent = nextFieldLabel != null;
                        if (nextFieldLabel == null)
                        {
                            nextFieldLabel = il.DefineLabel();
                        }

                        // Read field id
                        il.Emit(OpCodes.Ldarg_0);                                                  // Load stream
                        il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamReader(typeof(string))); // Read field id
                        il.Emit(OpCodes.Stloc_2);                                                  // Save last readed field id

                        // Mark next field label only after field read
                        if (markCurrent)
                        {
                            il.MarkLabel(nextFieldLabel.Value);
                            nextFieldLabel = il.DefineLabel();
                        }

                        // Compare field id with endToken
                        il.Emit(OpCodes.Ldloc_2);                               // Load readed field id
                        il.Emit(OpCodes.Ldstr, SerializerTypes.TypeEndToken);   // Load endToken id
                        il.Emit(OpCodes.Ldc_I4, (int)StringComparison.Ordinal); // Load comparsion type
                        il.Emit(OpCodes.Call, stringEquals);                    // Compare
                        il.Emit(OpCodes.Brtrue, resultLabel);                   // This is the end

                        // Compare field ids, if it not equals then skip read
                        il.Emit(OpCodes.Ldloc_2);                               // Load readed field id
                        il.Emit(OpCodes.Ldstr, binField.Id);                    // Load field id
                        il.Emit(OpCodes.Ldc_I4, (int)StringComparison.Ordinal); // Load comparsion type
                        il.Emit(OpCodes.Call, stringEquals);                    // Compare
                        il.Emit(OpCodes.Brfalse, nextFieldLabel.Value);         // These aren't the field your looking for

                        var deserialize = typeof(BinSerializer <>)
                                          .MakeGenericType(binField.Type)
                                          .GetTypeInfo()
                                          .GetMethod(nameof(BinSerializer <object> .Deserialize), BindingFlags.Static | BindingFlags.Public);

                        // Prepeare stack to field set
                        if (type.TypeInfo.IsValueType)
                        {
                            il.Emit(OpCodes.Ldloca_S, (byte)1);
                        }
                        else
                        {
                            il.Emit(OpCodes.Ldloc_1);
                        }

                        // Read field
                        il.Emit(OpCodes.Ldarg_0); // Load stream
                        il.Emit(OpCodes.Call, deserialize);

                        // Set field
                        binField.EmitWrite(il);
                    }

                    // Mark jump (for last field)
                    if (nextFieldLabel != null)
                    {
                        il.MarkLabel(nextFieldLabel.Value);
                    }

                    // Skip end
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamSkiper(typeof(string)));
                }
            }

            // Return result and invoke callback
            il.MarkLabel(resultLabel);

            // Invoke deserialzation callback
            if (typeof(IBinSerializable).IsAssignableFrom(type.Type))
            {
                il.Emit(OpCodes.Ldloca_S, (byte)4); // Load result local address
                il.Emit(OpCodes.Ldloc_3);           // Load version
                il.Emit(OpCodes.Call, typeof(DeserializationInfo).GetConstructor(new Type[] { typeof(int) }));

                il.Emit(OpCodes.Ldloc_1);                  // Load deserialized object
                il.Emit(OpCodes.Ldloc_S, (byte)4);         // Load created DeserialzationInfo
                il.Emit(OpCodes.Callvirt, onDeserialized); // Call onDeserialized
            }

            // Return result
            il.Emit(OpCodes.Ldloc_1);

            BSDebug.TraceEnd(il, "Read " + type.TypeInfo.Name);

            il.Emit(OpCodes.Ret);
        }
        private static void GenerateArrayReader(ILGenerator il, TypeImpl type)
        {
            var elementType = type.TypeInfo.GetElementType();

            var addRef = typeof(RefReaderWatcher)
                         .GetTypeInfo()
                         .GetMethod(nameof(RefReaderWatcher.AddRef), BindingFlags.Public | BindingFlags.Static)
                         .MakeGenericMethod(type.Type);

            var tryGetRef = typeof(RefReaderWatcher)
                            .GetTypeInfo()
                            .GetMethod(nameof(RefReaderWatcher.TryGetRef), BindingFlags.Public | BindingFlags.Static)
                            .MakeGenericMethod(type.Type);

            var deserialize = typeof(BinSerializer <>)
                              .MakeGenericType(elementType)
                              .GetTypeInfo()
                              .GetMethod(nameof(BinSerializer <object> .Deserialize), BindingFlags.Static | BindingFlags.Public);

            // array type id already was readed

            il.DeclareLocal(typeof(int)); // Ref id
            il.DeclareLocal(typeof(int)); // Array length
            il.DeclareLocal(typeof(int)); // Current index
            il.DeclareLocal(type.Type);   // Result array

            var loopLabel             = il.DefineLabel();
            var resultLabel           = il.DefineLabel();
            var tryLoadReferenceLabel = il.DefineLabel();

            // Read reference id
            il.Emit(OpCodes.Ldarg_0);                                               // Load stream
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamReader(typeof(int))); // Read ref id
            il.Emit(OpCodes.Dup);                                                   // Duplicate ref id
            il.Emit(OpCodes.Stloc_0);                                               // Set ref id to local

            // Check if result null
            il.Emit(OpCodes.Brtrue, tryLoadReferenceLabel); // Check if null was written

            // Null was written (return null)
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Stloc_3);         // Set result to null
            il.Emit(OpCodes.Br, resultLabel); // Jump to result

            // Try get readed reference
            il.MarkLabel(tryLoadReferenceLabel);
            il.Emit(OpCodes.Ldloc_0);             // Load reference id
            il.Emit(OpCodes.Ldloca_S, (byte)3);   // Load address of result
            il.Emit(OpCodes.Call, tryGetRef);
            il.Emit(OpCodes.Brtrue, resultLabel); // Jump to result if reference already exist

            // Read array length
            il.Emit(OpCodes.Ldarg_0);                                               // Load stream
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamReader(typeof(int))); // Read length
            il.Emit(OpCodes.Stloc_1);                                               // Set array length

            // Set current index
            il.Emit(OpCodes.Ldc_I4_0); // Load zero
            il.Emit(OpCodes.Stloc_2);  // Set current index

            // Create array
            il.Emit(OpCodes.Ldloc_1);             // Load array length
            il.Emit(OpCodes.Newarr, elementType); // Create array
            il.Emit(OpCodes.Stloc_3);             // Set array to local

            // Set ref id
            il.Emit(OpCodes.Ldloc_0); // Load reference id
            il.Emit(OpCodes.Ldloc_3); // Load result object reference
            il.Emit(OpCodes.Call, addRef);

            // Loop
            il.MarkLabel(loopLabel);

            // Check array end
            il.Emit(OpCodes.Ldloc_1); // Load length
            il.Emit(OpCodes.Ldloc_2); // Load index
            il.Emit(OpCodes.Beq, resultLabel);

            // Prepare set element
            il.Emit(OpCodes.Ldloc_3); // Load array
            il.Emit(OpCodes.Ldloc_2); // Load index

            // Read value
            il.Emit(OpCodes.Ldarg_0);           // Load stream
            il.Emit(OpCodes.Call, deserialize); // Deserialize element

            // Set element
            il.Emit(OpCodes.Stelem, elementType);

            // Inrement index
            il.Emit(OpCodes.Ldloc_2);  // Load index
            il.Emit(OpCodes.Ldc_I4_1); // Load one
            il.Emit(OpCodes.Add);      // Sum
            il.Emit(OpCodes.Stloc_2);  // Set index

            // Go to loop start
            il.Emit(OpCodes.Br, loopLabel);

            il.MarkLabel(resultLabel);
            il.Emit(OpCodes.Ldloc_3); // Load result array
            il.Emit(OpCodes.Ret);
        }
        private static void GenerateObjectWriter(ILGenerator il, TypeImpl type)
        {
            var getRefId = typeof(RefWriterWatcher)
                           .GetTypeInfo()
                           .GetMethod(nameof(RefWriterWatcher.GetRefId), BindingFlags.Public | BindingFlags.Static);
            var onSerializing = typeof(IBinSerializable).GetMethod(nameof(IBinSerializable.OnSerializing));

            il.DeclareLocal(typeof(bool));
            il.DeclareLocal(typeof(SerializationInfo));

            var skipTypeLabel = il.DefineLabel();

            BSDebug.TraceStart(il, "Write " + type.TypeInfo.Name);

            // Invoke deserialzation callback
            if (typeof(IBinSerializable).IsAssignableFrom(type.Type))
            {
                il.Emit(OpCodes.Ldloca_S, (byte)1); // Load result local address
                il.Emit(OpCodes.Initobj, typeof(SerializationInfo));

                il.Emit(OpCodes.Ldarg_1);                 // Load serializing object
                il.Emit(OpCodes.Ldloc_1);                 // Load created SerializationInfo
                il.Emit(OpCodes.Callvirt, onSerializing); // Call onSerializing
            }

            // Write type
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, SerializerTypes.GetTypeId(type));
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(string)));

            if (!type.TypeInfo.IsValueType)
            {
                // Write refId
                il.Emit(OpCodes.Ldarg_0);           // Load stream
                il.Emit(OpCodes.Ldarg_1);           // Load obj
                il.Emit(OpCodes.Ldloca_S, (byte)0); // Load address of bool local
                il.Emit(OpCodes.Call, getRefId);    // Obj => RefId
                il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(int)));

                // Check case when reference type already serialized.
                // If null be returned then created flag be zero too and serialization will be skipped.
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Brfalse, skipTypeLabel);
            }

            // Write type version
            var version = SerializerTypes.GetVersion(type);

            il.Emit(OpCodes.Ldarg_0);         // Load stream
            il.Emit(OpCodes.Ldc_I4, version); // Load version
            il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(int)));

            // If writer exist then just write
            var writer = SerializerTypes.TryGetStreamWriter(type) ?? SerializerTypes.TryGetTypeWriter(type);

            if (writer != null)
            {
                il.Emit(OpCodes.Ldarg_0);      // Load stream
                il.Emit(OpCodes.Ldarg_1);      // Load obj
                il.Emit(OpCodes.Call, writer); // Write to stream
            }
            else
            {
                foreach (var binField in BinField.Get(type.Type))
                {
                    var skipFieldLabel = il.DefineLabel();

                    // If field is null then skip it
                    if (!binField.IsValueType)
                    {
                        il.Emit(OpCodes.Ldarg_1);                 // Load object
                        binField.EmitRead(il);                    // Read field form object
                        il.Emit(OpCodes.Brfalse, skipFieldLabel); // Skip if field is null
                    }

                    // Write field id
                    il.Emit(OpCodes.Ldarg_0);            // Load stream
                    il.Emit(OpCodes.Ldstr, binField.Id); // Load field id
                    il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(string)));

                    var serialize = typeof(BinSerializer <>)
                                    .MakeGenericType(binField.Type)
                                    .GetTypeInfo()
                                    .GetMethod(nameof(BinSerializer <object> .Serialize), BindingFlags.Static | BindingFlags.Public);

                    // Write field
                    il.Emit(OpCodes.Ldarg_0);         // Load stream
                    il.Emit(OpCodes.Ldarg_1);         // Load object
                    binField.EmitRead(il);            // Read field from object
                    il.Emit(OpCodes.Call, serialize); // Write field value

                    // Skip field label
                    il.MarkLabel(skipFieldLabel);
                }

                // Write end id
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldstr, SerializerTypes.TypeEndToken);
                il.Emit(OpCodes.Call, SerializerTypes.TryGetStreamWriter(typeof(string)));
            }

            // Skip type label
            il.MarkLabel(skipTypeLabel);

            BSDebug.TraceEnd(il, "Write " + type.TypeInfo.Name);

            // End
            il.Emit(OpCodes.Ret);
        }