private void ToBytesEnumerable(IEnumerable values, int length, SerializerTypeDetails typeDetail, ref ByteWriter writer) { writer.Write(length); //object count if (typeDetail.TypeDetail.CoreType.HasValue) { ToBytesCoreTypeEnumerable(values, length, typeDetail.TypeDetail.CoreType.Value, ref writer); return; } if (typeDetail.TypeDetail.EnumUnderlyingType.HasValue) { ToBytesEnumTypeEnumerable(values, length, typeDetail.TypeDetail.EnumUnderlyingType.Value, ref writer); return; } if (typeDetail.TypeDetail.SpecialType.HasValue || typeDetail.TypeDetail.IsNullable && typeDetail.InnerTypeDetail.TypeDetail.SpecialType.HasValue) { ToBytesSpecialTypeEnumerable(values, length, typeDetail, ref writer); return; } foreach (var value in values) { if (value == null) { writer.Write(false); //no object continue; } writer.Write(true); //has object ToBytes(value, typeDetail, false, ref writer); } }
private void ToBytesSpecialTypeEnumerable(IEnumerable values, int length, SerializerTypeDetails typeDetail, ref ByteWriter writer) { var specialType = typeDetail.TypeDetail.IsNullable ? typeDetail.InnerTypeDetail.TypeDetail.SpecialType.Value : typeDetail.TypeDetail.SpecialType.Value; switch (specialType) { case SpecialType.Type: { foreach (var valueType in (IEnumerable <Type>)values) { writer.Write(valueType?.FullName, true); } return; } case SpecialType.Dictionary: { foreach (var value in values) { if (value != null) { writer.WriteNotNull(); var method = TypeAnalyzer.GetGenericMethodDetail(enumerableToArrayMethod, typeDetail.TypeDetail.IEnumerableGenericInnerType); var innerValue = (ICollection)method.Caller(null, new object[] { value }); var count = innerValue.Count; ToBytesEnumerable(innerValue, count, typeDetail.InnerTypeDetail, ref writer); } else { writer.WriteNull(); } } return; } default: throw new NotImplementedException(); } }
private void ToBytesSpecialType(object value, SerializerTypeDetails typeDetail, bool nullFlags, ref ByteWriter writer) { var specialType = typeDetail.TypeDetail.IsNullable ? typeDetail.InnerTypeDetail.TypeDetail.SpecialType.Value : typeDetail.TypeDetail.SpecialType.Value; switch (specialType) { case SpecialType.Type: { var valueType = value == null ? null : (Type)value; writer.Write(valueType?.FullName, nullFlags); } return; case SpecialType.Dictionary: { if (value != null) { if (nullFlags) { writer.WriteNotNull(); } var method = TypeAnalyzer.GetGenericMethodDetail(enumerableToArrayMethod, typeDetail.TypeDetail.IEnumerableGenericInnerType); var innerValue = (ICollection)method.Caller(null, new object[] { value }); var count = innerValue.Count; ToBytesEnumerable(innerValue, count, typeDetail.InnerTypeDetail, ref writer); } else if (nullFlags) { writer.WriteNull(); } } return; default: throw new NotImplementedException(); } }
private void ToBytes(object value, SerializerTypeDetails typeDetail, bool nullFlags, ref ByteWriter writer) { if (includePropertyTypes) { var typeFromValue = value.GetType(); string typeName = typeFromValue.FullName; writer.Write(typeName, false); typeDetail = GetTypeInformation(typeFromValue, this.indexSize, this.ignoreIndexAttribute); } else if (typeDetail.Type.IsInterface && !typeDetail.TypeDetail.IsIEnumerableGeneric && value != null) { var objectType = value.GetType(); typeDetail = GetTypeInformation(objectType, this.indexSize, this.ignoreIndexAttribute); } else if (typeDetail == null) { throw new InvalidOperationException("Must include type information to deserialize without specifying a type."); } if (typeDetail.TypeDetail.CoreType.HasValue) { ToBytesCoreType(value, typeDetail.TypeDetail.CoreType.Value, nullFlags, ref writer); return; } if (typeDetail.TypeDetail.EnumUnderlyingType.HasValue) { ToBytesEnumType(value, typeDetail.TypeDetail.EnumUnderlyingType.Value, nullFlags, ref writer); return; } if (typeDetail.TypeDetail.SpecialType.HasValue || typeDetail.TypeDetail.IsNullable && typeDetail.InnerTypeDetail.TypeDetail.SpecialType.HasValue) { ToBytesSpecialType(value, typeDetail, nullFlags, ref writer); return; } if (typeDetail.TypeDetail.IsIEnumerableGeneric) { if (typeDetail.TypeDetail.IsICollection) { var collection = (ICollection)value; var count = collection.Count; ToBytesEnumerable(collection, count, typeDetail.InnerTypeDetail, ref writer); } else if (typeDetail.TypeDetail.IsICollectionGeneric) { var count = (int)typeDetail.TypeDetail.GetMember("Count").Getter(value); ToBytesEnumerable((IEnumerable)value, count, typeDetail.InnerTypeDetail, ref writer); } else { var enumerable = (IEnumerable)value; var count = 0; foreach (var item in enumerable) { count++; } ToBytesEnumerable(enumerable, count, typeDetail.InnerTypeDetail, ref writer); } return; } if (nullFlags) { if (value == null) { writer.Write(false); //no object return; } writer.Write(true); //has object } foreach (var indexProperty in typeDetail.IndexedProperties) { object propertyValue = indexProperty.Value.Getter(value); if (propertyValue != null) { if (usePropertyNames) { writer.Write(indexProperty.Value.Name, false); } else { switch (this.indexSize) { case ByteSerializerIndexSize.Byte: writer.Write((byte)indexProperty.Key); break; case ByteSerializerIndexSize.UInt16: writer.Write(indexProperty.Key); break; default: throw new NotImplementedException(); } } ToBytes(propertyValue, indexProperty.Value.SerailzierTypeDetails, false, ref writer); } } if (usePropertyNames) { writer.Write(0); } else { switch (this.indexSize) { case ByteSerializerIndexSize.Byte: writer.Write(endObjectFlagByte); break; case ByteSerializerIndexSize.UInt16: writer.Write(endObjectFlagUInt16); break; default: throw new NotImplementedException(); } } }
private object FromBytes(ref ByteReader reader, SerializerTypeDetails typeDetail, bool nullFlags, bool drainBytes) { if (!drainBytes && typeDetail == null) { throw new NotSupportedException("Cannot deserialize without type information"); } if (includePropertyTypes) { string typeName = reader.ReadString(false); var typeFromBytes = Discovery.GetTypeFromName(typeName); //overrides potentially boxed type with actual type if exists in assembly if (typeFromBytes != null) { var newTypeDetail = GetTypeInformation(typeFromBytes, this.indexSize, this.ignoreIndexAttribute); var typeDetailCheck = typeDetail.TypeDetail; if (typeDetailCheck.IsNullable) { typeDetailCheck = typeDetailCheck.InnerTypeDetails[0]; } var newTypeDetailCheck = newTypeDetail.TypeDetail; if (newTypeDetailCheck.Type != typeDetailCheck.Type && !newTypeDetailCheck.Interfaces.Contains(typeDetailCheck.Type) && !newTypeDetail.TypeDetail.BaseTypes.Contains(typeDetailCheck.Type)) { throw new NotSupportedException($"{newTypeDetail.Type.GetNiceName()} does not convert to {typeDetail.TypeDetail.Type.GetNiceName()}"); } typeDetail = newTypeDetail; } } else if (typeDetail.Type.IsInterface && !typeDetail.TypeDetail.IsIEnumerableGeneric) { var emptyImplementationType = EmptyImplementations.GetEmptyImplementationType(typeDetail.Type); typeDetail = GetTypeInformation(emptyImplementationType, this.indexSize, this.ignoreIndexAttribute); } if (typeDetail.TypeDetail.CoreType.HasValue) { return(FromBytesCoreType(ref reader, typeDetail.TypeDetail.CoreType.Value, nullFlags)); } if (typeDetail.TypeDetail.EnumUnderlyingType.HasValue) { var numValue = FromBytesCoreType(ref reader, typeDetail.TypeDetail.EnumUnderlyingType.Value, nullFlags); object value; if (!typeDetail.TypeDetail.IsNullable) { value = Enum.ToObject(typeDetail.Type, numValue); } else if (numValue != null) { value = Enum.ToObject(typeDetail.TypeDetail.InnerTypes[0], numValue); } else { value = null; } return(value); } if (typeDetail.TypeDetail.SpecialType.HasValue || typeDetail.TypeDetail.IsNullable && typeDetail.InnerTypeDetail.TypeDetail.SpecialType.HasValue) { return(FromBytesSpecialType(ref reader, typeDetail, nullFlags)); } if (typeDetail.TypeDetail.IsIEnumerableGeneric) { var enumerable = FromBytesEnumerable(ref reader, typeDetail.InnerTypeDetail, !typeDetail.TypeDetail.Type.IsArray && typeDetail.TypeDetail.IsIList); return(enumerable); } if (nullFlags) { var hasObject = reader.ReadBoolean(); if (!hasObject) { return(null); } } object obj = typeDetail.TypeDetail.Creator(); for (; ;) { SerializerMemberDetails indexProperty = null; if (usePropertyNames) { string name = reader.ReadString(false); if (name == String.Empty) { return(obj); } indexProperty = typeDetail.IndexedProperties.Values.FirstOrDefault(x => x.Name == name); if (indexProperty == null) { if (!usePropertyNames && !includePropertyTypes) { throw new Exception($"Cannot deserialize with property {name} undefined and no types."); } //consume bytes but object does not have property object value = FromBytes(ref reader, null, false, true); indexProperty.Setter(obj, value); } else { object value = FromBytes(ref reader, indexProperty.SerailzierTypeDetails, false, false); indexProperty.Setter(obj, value); } } else { var propertyIndex = this.indexSize switch { ByteSerializerIndexSize.Byte => (ushort)reader.ReadByte(), ByteSerializerIndexSize.UInt16 => reader.ReadUInt16(), _ => throw new NotImplementedException(), }; if (propertyIndex == endObjectFlagUShort) { return(obj); } if (typeDetail.IndexedProperties.Keys.Contains(propertyIndex)) { indexProperty = typeDetail.IndexedProperties[propertyIndex]; } if (indexProperty == null) { if (!usePropertyNames && !includePropertyTypes) { throw new Exception($"Cannot deserialize with property {propertyIndex} undefined and no types."); } //consume bytes but object does not have property object value = FromBytes(ref reader, null, false, true); indexProperty.Setter(obj, value); } else { object value = FromBytes(ref reader, indexProperty.SerailzierTypeDetails, false, false); indexProperty.Setter(obj, value); } } } throw new Exception("Expected end of object marker"); }
private object FromBytesEnumerable(ref ByteReader reader, SerializerTypeDetails typeDetail, bool asList) { int length = reader.ReadInt32(); if (length == 0) { if (!asList) { return(Array.CreateInstance(typeDetail.Type, length)); } else { return((IList)typeDetail.ListCreator(length)); } } if (typeDetail.TypeDetail.CoreType.HasValue) { return(FromBytesCoreTypeEnumerable(ref reader, length, typeDetail.TypeDetail.CoreType.Value, asList)); } if (typeDetail.TypeDetail.EnumUnderlyingType.HasValue) { if (!asList) { var array = Array.CreateInstance(typeDetail.Type, length); for (int i = 0; i < length; i++) { var numValue = FromBytesCoreType(ref reader, typeDetail.TypeDetail.EnumUnderlyingType.Value, true); object item; if (!typeDetail.TypeDetail.IsNullable) { item = Enum.ToObject(typeDetail.Type, numValue); } else if (numValue != null) { item = Enum.ToObject(typeDetail.TypeDetail.InnerTypes[0], numValue); } else { item = null; } array.SetValue(item, i); } return(array); } else { var list = (IList)typeDetail.ListCreator(length); for (int i = 0; i < length; i++) { var numValue = FromBytesCoreType(ref reader, typeDetail.TypeDetail.EnumUnderlyingType.Value, true); object item; if (!typeDetail.TypeDetail.IsNullable) { item = Enum.ToObject(typeDetail.Type, numValue); } else if (numValue != null) { item = Enum.ToObject(typeDetail.TypeDetail.InnerTypes[0], numValue); } else { item = null; } list.Add(item); } return(list); } } if (typeDetail.TypeDetail.SpecialType.HasValue || typeDetail.TypeDetail.IsNullable && typeDetail.InnerTypeDetail.TypeDetail.SpecialType.HasValue) { return(FromBytesSpecialTypeEnumerable(ref reader, length, typeDetail, asList)); } object obj = null; if (!asList) { var array = Array.CreateInstance(typeDetail.Type, length); if (length == 0) { return(array); } int count = 0; for (; ;) { var hasObject = reader.ReadBoolean(); if (!hasObject) { count++; if (count == length) { return(array); } continue; } obj = FromBytes(ref reader, typeDetail, false, false); array.SetValue(obj, count); count++; if (count == length) { return(array); } } throw new Exception("Expected end of object marker"); } else { var list = (IList)typeDetail.ListCreator(length); if (length == 0) { return(list); } int count = 0; for (; ;) { var hasObject = reader.ReadBoolean(); if (!hasObject) { list.Add(null); count++; if (count == length) { return(list); } continue; } obj = FromBytes(ref reader, typeDetail, false, false); list.Add(obj); count++; if (count == length) { return(list); } } throw new Exception("Expected end of object marker"); } }