public static object Deserialize( BinaryReader reader, Type type, bool isNullableIfReferenceType, bool areElementsNullableIfReferenceType ) { var nullableUnderlyingType = Nullable.GetUnderlyingType(type); if ((nullableUnderlyingType == null) && isNullableIfReferenceType && type.IsClass) { nullableUnderlyingType = type; } if (nullableUnderlyingType != null) { var objHasValue = reader.ReadBoolean(); return(objHasValue ? Deserialize( reader, nullableUnderlyingType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: areElementsNullableIfReferenceType ) : null); } else if (type == typeof(bool)) { return(reader.ReadBoolean()); } else if (type == typeof(sbyte)) { return(reader.ReadSByte()); } else if (type == typeof(byte)) { return(reader.ReadByte()); } else if (type == typeof(ushort)) { return(reader.ReadUInt16()); } else if (type == typeof(short)) { return(reader.ReadInt16()); } else if (type == typeof(uint)) { return(reader.ReadUInt32()); } else if (type == typeof(int)) { return(reader.ReadInt32()); } else if (type == typeof(ulong)) { return(reader.ReadUInt64()); } else if (type == typeof(long)) { return(reader.ReadInt64()); } else if (type == typeof(float)) { return(reader.ReadSingle()); } else if (type == typeof(double)) { return(reader.ReadDouble()); } else if (type == typeof(decimal)) { return(reader.ReadDecimal()); } else if (type == typeof(char)) { return(reader.ReadChar()); } else if (type == typeof(string)) { return(reader.ReadString()); } else if (type == typeof(float2)) { var result = new float2(); Deserialize(reader, ref result); return(result); } else if (type == typeof(float3)) { var result = new float3(); Deserialize(reader, ref result); return(result); } else if (type == typeof(float4)) { var result = new float4(); Deserialize(reader, ref result); return(result); } else if (type == typeof(Vector2)) { var result = new Vector2(); Deserialize(reader, ref result); return(result); } else if (type == typeof(Vector3)) { var result = new Vector3(); Deserialize(reader, ref result); return(result); } else if (type == typeof(Vector4)) { var result = new Vector4(); Deserialize(reader, ref result); return(result); } else if (typeof(INetworkSerializable).IsAssignableFrom(type)) { var result = Activator.CreateInstance(type); ((INetworkSerializable)result).Deserialize(reader); return(result); } else if (typeof(IEnumerable).IsAssignableFrom(type)) { if (typeof(Array).IsAssignableFrom(type)) { var elementType = type.GetElementType(); var elementCount = reader.ReadUInt32(); var array = Array.CreateInstance(elementType, elementCount); for (var i = 0; i < elementCount; i++) { var element = Deserialize( reader, elementType, isNullableIfReferenceType: areElementsNullableIfReferenceType, areElementsNullableIfReferenceType: false ); array.SetValue(element, i); } return(array); } else if (typeof(IList).IsAssignableFrom(type)) { var list = (IList)Activator.CreateInstance(type); var elementType = type.GenericTypeArguments[0]; var elementCount = reader.ReadUInt32(); for (var i = 0; i < elementCount; i++) { var element = Deserialize( reader, elementType, isNullableIfReferenceType: areElementsNullableIfReferenceType, areElementsNullableIfReferenceType: false ); list.Add(element); } return(list); } else { throw new NotImplementedException(); } } else { if (type.IsEnum) { var smallestTypeToHoldEnumValues = GetSmallestUIntTypeToHoldEnumValues(type); var enumValueAsInt = Deserialize( reader, smallestTypeToHoldEnumValues, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); return(Enum.ToObject(type, enumValueAsInt)); } else if (type.IsClass || type.IsValueType) { var result = Activator.CreateInstance(type); var objFields = NetLib.GetFieldInfosToSerialize(type); foreach (var objField in objFields) { var fieldValue = Deserialize( reader, objField.FieldType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); objField.SetValue(result, fieldValue); } var objProperties = NetLib.GetPropertyInfosToSerialize(type); foreach (var objProperty in objProperties) { if (!objProperty.CanRead || !objProperty.CanWrite) { continue; } var propertyValue = Deserialize( reader, objProperty.PropertyType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); objProperty.SetValue(result, propertyValue); } return(result); } else { throw new NotImplementedException($"Cannot deserialize type: {type.AssemblyQualifiedName}"); } } }
public static void SerializeObject( BinaryWriter writer, object obj, Type overrideType, bool isNullableIfReferenceType, bool areElementsNullableIfReferenceType ) { Assert.IsTrue(!isNullableIfReferenceType || (overrideType != null)); var objType = overrideType ?? obj?.GetType(); Assert.IsNotNull(objType); Assert.IsTrue((obj != null) || !objType.IsClass || isNullableIfReferenceType); var nullableUnderlyingType = Nullable.GetUnderlyingType(objType); if ((nullableUnderlyingType == null) && isNullableIfReferenceType && objType.IsClass) { nullableUnderlyingType = objType; } if (nullableUnderlyingType != null) { writer.Write(obj != null); if (obj != null) { objType = nullableUnderlyingType; } else { return; } } if (objType == typeof(bool)) { writer.Write((bool)obj); } else if (objType == typeof(sbyte)) { writer.Write((sbyte)obj); } else if (objType == typeof(byte)) { writer.Write((byte)obj); } else if (objType == typeof(ushort)) { writer.Write((ushort)obj); } else if (objType == typeof(short)) { writer.Write((short)obj); } else if (objType == typeof(uint)) { writer.Write((uint)obj); } else if (objType == typeof(int)) { writer.Write((int)obj); } else if (objType == typeof(ulong)) { writer.Write((ulong)obj); } else if (objType == typeof(long)) { writer.Write((long)obj); } else if (objType == typeof(float)) { writer.Write((float)obj); } else if (objType == typeof(double)) { writer.Write((double)obj); } else if (objType == typeof(decimal)) { writer.Write((decimal)obj); } else if (objType == typeof(char)) { writer.Write((char)obj); } else if (objType == typeof(string)) { writer.Write((string)obj); } else if (objType == typeof(float2)) { Serialize(writer, (float2)obj); } else if (objType == typeof(float3)) { Serialize(writer, (float3)obj); } else if (objType == typeof(float4)) { Serialize(writer, (float4)obj); } else if (objType == typeof(Vector2)) { Serialize(writer, (Vector2)obj); } else if (objType == typeof(Vector3)) { Serialize(writer, (Vector3)obj); } else if (objType == typeof(Vector4)) { Serialize(writer, (Vector4)obj); } else if (typeof(INetworkSerializable).IsAssignableFrom(obj.GetType())) { ((INetworkSerializable)obj).Serialize(writer); } else if (typeof(ICollection).IsAssignableFrom(objType)) { Type elementType; if (objType.IsArray) { elementType = objType.GetElementType(); } else if (objType.IsGenericType) { elementType = objType.GetGenericArguments()[0]; } else { throw new NotImplementedException("Non-generic collections aren't supported."); } var collection = (ICollection)obj; writer.Write((uint)collection.Count); foreach (var element in collection) { SerializeObject( writer, element, overrideType: elementType, isNullableIfReferenceType: areElementsNullableIfReferenceType, areElementsNullableIfReferenceType: false ); } } else { if (objType.IsEnum) { var smallestTypeToHoldEnumValues = GetSmallestUIntTypeToHoldEnumValues(objType); var objToSerialize = Convert.ChangeType(obj, smallestTypeToHoldEnumValues); SerializeObject( writer, objToSerialize, overrideType: null, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); } else if (objType.IsClass || objType.IsValueType) { var objFields = NetLib.GetFieldInfosToSerialize(objType); foreach (var objField in objFields) { SerializeObject( writer, objField.GetValue(obj), objField.FieldType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); } var objProperties = NetLib.GetPropertyInfosToSerialize(objType); foreach (var objProperty in objProperties) { if (!objProperty.CanRead || !objProperty.CanWrite) { continue; } SerializeObject( writer, objProperty.GetValue(obj), objProperty.PropertyType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); } } else { throw new NotImplementedException($"Cannot serialize type: {objType.AssemblyQualifiedName}"); } } }