public void Serialize(object obj, SerializationOptions options) { if (obj == null) { Write("null"); return; } var objectType = obj.GetType(); var converter = options?.Converters?.FirstOrDefault(c => c.GetConvertingType() == objectType); if (converter != null) { Serialize(converter.Serializer(obj), options); return; } Func <object, string> cnv; Type genericType; if (!SerializerCache.TryGetValue(objectType, out cnv)) { var strConverter = new Func <object, string>( s => { var t = (string)s; var r = "\""; for (var i = 0; i < t.Length; i++) { var c = t[i]; r += c == '\r' ? "\\r" : c == '\n' ? "\\n" : c == '\t' ? "\\t" : c == '"' ? "\\\"" : c == '\\' ? "\\\\" : c == '/' ? "\\/" : c == '\b' ? "\\b" : c == '\f' ? "\\f" : c.ToString(); } r += "\""; return(r); }); if (obj is string) { cnv = strConverter; } else if (obj is IEnumerable) { Write(obj is IDictionary ? "{" : "["); var first = true; foreach (var o in (IEnumerable)obj) { if (first) { first = false; } else { Write(","); } Serialize(o, options); } Write(obj is IDictionary ? "}" : "]"); return; } else if (obj is bool || obj is bool?) { cnv = b => (bool)b ? "true" : "false"; } else if (obj is int || obj is int? || obj is short || obj is short? || obj is long || obj is long? || obj is uint || obj is uint? || obj is ushort || obj is ushort? || obj is ulong || obj is ulong? || obj is float || obj is float? || obj is double || obj is double? || obj is decimal || obj is decimal?|| obj is float || obj is uint? || obj is ushort || obj is ushort? || obj is ulong || obj is ulong?) { cnv = n => string.Format(CultureInfo.InvariantCulture, "{0}", n); } else if (obj is DateTime || obj is DateTime?) { cnv = d => strConverter(((DateTime)d).ToString(CultureInfo.InvariantCulture)); } else if (obj is DateTimeOffset || obj is DateTimeOffset?) { cnv = d => strConverter(((DateTimeOffset)d).ToString(CultureInfo.InvariantCulture)); } else if (obj is TimeSpan || obj is TimeSpan?) { cnv = d => strConverter(((TimeSpan)d).ToString("c")); } else if (obj is Enum) { cnv = e => ((int)e).ToString(CultureInfo.InvariantCulture); } else if (objectType.IsGenericType && objectType.GenericTypeArguments.Length == 2 && objectType == (genericType = typeof(KeyValuePair <,>).MakeGenericType(objectType.GenericTypeArguments))) { var k = genericType.GetProperty("Key").GetValue(obj).ToString(); var v = genericType.GetProperty("Value").GetValue(obj); Write(strConverter(k)); Write(":"); Serialize(v, options); return; } else if (!objectType.IsPrimitive) { Write("{"); var first = true; foreach (var m in SerializerMap.GetSerializerMap(objectType) .Members) { if (first) { first = false; } else { Write(","); } if (objectType == typeof(DictionaryEntry)) { var d = (DictionaryEntry)obj; Write(strConverter(d.Key.ToString())); Write(":"); Serialize(d.Value, options); } else { string memberName = m.Name; if (options?.PropertyNameTransform != null) { memberName = options?.PropertyNameTransform.Transform(m.Name); } Write(strConverter(memberName)); Write(":"); try { Serialize(m.GetValue(obj), options); } catch (TargetInvocationException) { Serialize(null, options); } } } Write("}"); return; } SerializerCache[objectType] = cnv ?? throw new InvalidOperationException( "Unknown object type! " + objectType.FullName);; } Write(cnv(obj)); }
public object FromJson(Type type) { object result; SkipWhite(); if (NextChar == '{') { ReadNext(); SkipWhite(); if (type.IsValueType) { throw new FormatException("Unexpected type!"); } result = Activator.CreateInstance(type); var nameType = result is IDictionary ? type.GenericTypeArguments[0] : typeof(string); var valueType = result is IDictionary ? type.GenericTypeArguments[1] : null; var mIndex = 0; while (NextChar != '}') { var name = (string)FromJson(nameType); SkipWhite(); Match(":"); var map = SerializerMap.GetSerializerMap(type); MemberAccessor field = null; if (valueType == null) { for (var i = mIndex; i < map.Members.Length; i++) { string memberName = map.Members[i].Name; if (PropertyNameTransform != null) { memberName = PropertyNameTransform.Transform(memberName); } if (memberName == name) { field = map.Members[i]; break; } } } var fieldType = field == null ? valueType : field.ValueType; var value = FromJson(fieldType); if (field != null) { field.SetValue(result, value); } else { ((IDictionary)result).Add(name, value); } SkipWhite(); if (NextChar == ',') { ReadNext(); SkipWhite(); continue; } break; } Match("}"); return(result); } if (NextChar == '[') { ReadNext(); SkipWhite(); var elementType = type.IsArray ? type.GetElementType() : type.IsGenericType ? type.GenericTypeArguments[0] : typeof(object); var list = type.IsArray ? new ArrayList() : (IList)Activator.CreateInstance(type); while (NextChar != ']') { var item = FromJson(elementType); list.Add(item); SkipWhite(); if (NextChar == ',') { ReadNext(); SkipWhite(); continue; } break; } Match("]"); if (list is ArrayList) { return(((ArrayList)list).ToArray(elementType)); } else { return(list); } } if (NextChar == '"') { ReadNext(); while (!EndOfStream && NextChar != '"') { if (NextChar == '\\') { ReadNext(); switch (NextChar) { case 'b': case 't': case 'n': case 'f': case 'r': text.Append(EscapeMap[NextChar]); break; case 'u': ReadNext(); var unicode = ""; while (unicode.Length < 4 && IsHexDigit) { unicode += NextChar; ReadNext(); } text.Append(char.ConvertFromUtf32(int.Parse("0x" + unicode))); continue; default: text.Append(NextChar); break; } } else { text.Append(NextChar); } ReadNext(); } SkipWhite(); Match("\""); result = text.ToString(); text.Clear(); var converter = Converters?.FirstOrDefault(c => c.GetConvertingType() == type); if (converter != null) { return(converter.Deserializer((string)result)); } if (type == typeof(DateTime) || type == typeof(DateTime?)) { return(DateTime.Parse((string)result, CultureInfo.InvariantCulture)); } if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) { return(DateTimeOffset.Parse((string)result, CultureInfo.InvariantCulture)); } if (type == typeof(TimeSpan) || type == typeof(TimeSpan?)) { return(TimeSpan.Parse((string)result, CultureInfo.InvariantCulture)); } return(result); } else if (NextChar == 't') { Match("true"); return(true); } else if (NextChar == 'f') { Match("false"); return(false); } else if (NextChar == 'n') { Match("null"); if (!(type.IsClass || Nullable.GetUnderlyingType(type) != null)) { throw new InvalidDataException("Type " + type.Name + "'s value cannot be null!"); } return(null); } else if (NextChar == '-' || IsDigit) { if (NextChar == '-') { text.Append('-'); ReadNext(); } if (NextChar == '0') { text.Append('0'); ReadNext(); } else if (IsDigit) { do { text.Append(NextChar); ReadNext(); }while (IsDigit); } else { throw new FormatException("Digit expected!"); } if (NextChar == '.') { text.Append('.'); ReadNext(); while (IsDigit) { text.Append(NextChar); ReadNext(); } } if (NextChar == 'e' || NextChar == 'E') { text.Append('e'); ReadNext(); if (NextChar == '+' || NextChar == '-') { text.Append(NextChar); ReadNext(); } while (IsDigit) { text.Append(NextChar); ReadNext(); } } var t = text.ToString(); text.Clear(); var inv = CultureInfo.InvariantCulture; if (type.IsEnum || type == typeof(int) || type == typeof(int?)) { return(int.Parse(t, inv)); } if (type == typeof(long) || type == typeof(long?)) { return(long.Parse(t, inv)); } return(double.Parse(t, inv)); } throw new FormatException("Unexpected character! " + NextChar); }