private void SerializeValue(string name, Type type, object value, IValueWriter writer, Type collectionItemType = null, int?index = null) { var valueInfo = new ValueInfo { Name = name, Index = index }; if (value != null) { type = value.GetType(); } var writeValueAsReference = false; if (value != null && !type.IsValueType() && type != typeof(string) && type != typeof(Uri)) { var objectId = _idGenerator.GetId(value, out var isFirstTime); if (_specialIds.TryGetValue(objectId, out var specialId)) { valueInfo.SpecialId = specialId; writeValueAsReference = true; } else { valueInfo.ReferenceId = objectId; writeValueAsReference = !isFirstTime; } } if (value is Type valueAsType) { valueInfo.Type = GetTypeSerializationInfo(valueAsType); type = typeof(Type); } if (writeValueAsReference) { // Reset other fields, because they don't need to be written. valueInfo.Type = null; valueInfo.ItemType = null; valueInfo.ItemCount = null; writer.WriteStartValue(valueInfo); writer.WriteEndValue(); } else if (value == null) { writer.WriteStartValue(valueInfo); writer.WriteValue(null); writer.WriteEndValue(); } else if (writer.CanWriteValueWithoutTypeInfo(type)) { writer.WriteStartValue(valueInfo); writer.WriteValue(value); writer.WriteEndValue(); } else if (type.IsEnum()) { writer.WriteStartValue(valueInfo); value = Convert.ChangeType(value, type.GetEnumUnderlyingType()); writer.WriteValue(value); writer.WriteEndValue(); } #warning Treat other types of collections as arrays else if (type.IsArray) { var items = (IList)value; var itemType = type.GetElementType(); valueInfo.IsCollection = true; #warning Write collection type //valueInfo.Type = valueInfo.ItemType = itemType == typeof(object) || itemType == collectionItemType ? null : GetTypeSerializationInfo(itemType); valueInfo.ItemCount = items.Count; writer.WriteStartValue(valueInfo); var itemIndex = 0; foreach (var item in items) { SerializeValue(null, item?.GetType(), item, writer, collectionItemType: itemType, index: itemIndex++); } writer.WriteEndValue(); } else if (value is IValueContainer valueAsContainer) { writer.WriteStartValue(valueInfo); if (valueAsContainer.GetCount() == 0) { writer.WriteValue(null); } else { SerializeValueContainer(valueAsContainer, writer); } writer.WriteEndValue(); } else { if (!TryDecomposeValue(type, value, out var typeInfo, out var nestedContainer)) { throw new UnserializableTypeException(type); } valueInfo.Type = typeInfo; writer.WriteStartValue(valueInfo); SerializeValueContainer(nestedContainer, writer); writer.WriteEndValue(); } }