public object ReadObject(Type type) { if (serialized_object_count++ == serializer.MaxItemsInObjectGraph) { throw SerializationError(String.Format("The object graph exceeded the maximum object count '{0}' specified in the serializer", serializer.MaxItemsInObjectGraph)); } bool nullable = false; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { nullable = true; type = Nullable.GetUnderlyingType(type); } bool isNull = reader.GetAttribute("type") == "null"; switch (Type.GetTypeCode(type)) { case TypeCode.DBNull: string dbn = reader.ReadElementContentAsString(); if (dbn != String.Empty) { throw new SerializationException(String.Format("The only expected DBNull value string is '{{}}'. Tha actual input was '{0}'.", dbn)); } return(DBNull.Value); case TypeCode.String: if (isNull) { reader.ReadElementContentAsString(); return(null); } else { return(reader.ReadElementContentAsString()); } case TypeCode.Char: var c = reader.ReadElementContentAsString(); if (c.Length > 1) { throw new XmlException("Invalid JSON char"); } return(Char.Parse(c)); case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return(ReadValueType(type, nullable)); case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.Int64: if (type.IsEnum) { return(Enum.ToObject(type, Convert.ChangeType(reader.ReadElementContentAsLong(), Enum.GetUnderlyingType(type), null))); } else { return(ReadValueType(type, nullable)); } case TypeCode.UInt64: if (type.IsEnum) { return(Enum.ToObject(type, Convert.ChangeType(reader.ReadElementContentAsDecimal(), Enum.GetUnderlyingType(type), null))); } else { return(ReadValueType(type, nullable)); } case TypeCode.Boolean: return(ReadValueType(type, nullable)); case TypeCode.DateTime: // it does not use ReadElementContentAsDateTime(). Different string format. var s = reader.ReadElementContentAsString(); if (s.Length < 2 || !s.StartsWith("/Date(", StringComparison.Ordinal) || !s.EndsWith(")/", StringComparison.Ordinal)) { if (nullable) { return(null); } throw new XmlException("Invalid JSON DateTime format. The value format should be '/Date(UnixTime)/'"); } // The date can contain [SIGN]LONG, [SIGN]LONG+HOURSMINUTES or [SIGN]LONG-HOURSMINUTES // the format for HOURSMINUTES is DDDD int tidx = s.IndexOf('-', 8); if (tidx == -1) { tidx = s.IndexOf('+', 8); } int minutes = 0; if (tidx == -1) { s = s.Substring(6, s.Length - 8); } else { int offset; int.TryParse(s.Substring(tidx + 1, s.Length - 3 - tidx), out offset); minutes = (offset % 100) + (offset / 100) * 60; if (s [tidx] == '-') { minutes = -minutes; } s = s.Substring(6, tidx - 6); } var date = new DateTime(1970, 1, 1).AddMilliseconds(long.Parse(s)); if (minutes != 0) { date = date.AddMinutes(minutes); } return(date); default: if (type == typeof(Guid)) { return(new Guid(reader.ReadElementContentAsString())); } else if (type == typeof(Uri)) { if (isNull) { reader.ReadElementContentAsString(); return(null); } else { return(new Uri(reader.ReadElementContentAsString(), UriKind.RelativeOrAbsolute)); } } else if (type == typeof(XmlQualifiedName)) { s = reader.ReadElementContentAsString(); int idx = s.IndexOf(':'); return(idx < 0 ? new XmlQualifiedName(s) : new XmlQualifiedName(s.Substring(0, idx), s.Substring(idx + 1))); } else if (type != typeof(object)) { // strongly-typed object if (reader.IsEmptyElement) { // empty -> null array or object reader.Read(); return(null); } Type ct = GetCollectionElementType(type); if (ct != null) { return(DeserializeGenericCollection(type, ct)); } else { TypeMap map = GetTypeMap(type); return(map.Deserialize(this)); } } else { return(ReadInstanceDrivenObject()); } } }
object DeserializeGenericCollection(Type collectionType, Type elementType, object collectionInstance) { reader.ReadStartElement(); object ret; if (collectionType.IsInterface) { collectionType = typeof(List <>).MakeGenericType(elementType); } if (TypeMap.IsDictionary(collectionType)) { if (collectionInstance == null) { collectionInstance = Activator.CreateInstance(collectionType); } var keyType = elementType.IsGenericType ? elementType.GetGenericArguments() [0] : typeof(object); var valueType = elementType.IsGenericType ? elementType.GetGenericArguments() [1] : typeof(object); MethodInfo add = collectionType.GetMethod("Add", new Type [] { keyType, valueType }); for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent()) { if (!reader.IsStartElement("item")) { throw SerializationError(String.Format("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI)); } // reading a KeyValuePair in the form of <Key .../><Value .../> reader.Read(); reader.MoveToContent(); object key = ReadObject(keyType); reader.MoveToContent(); object val = ReadObject(valueType); reader.Read(); add.Invoke(collectionInstance, new [] { key, val }); } ret = collectionInstance; } else if (typeof(IList).IsAssignableFrom(collectionType)) { #if NET_2_1 Type listType = collectionType.IsArray ? typeof(List <>).MakeGenericType(elementType) : null; #else Type listType = collectionType.IsArray ? typeof(ArrayList) : null; #endif IList c; if (collectionInstance == null) { c = (IList)Activator.CreateInstance(listType ?? collectionType); } else { c = (IList)collectionInstance; } for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent()) { if (!reader.IsStartElement("item")) { throw SerializationError(String.Format("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI)); } Type et = elementType == typeof(object) || elementType.IsAbstract ? null : elementType; object elem = ReadObject(et ?? typeof(object)); c.Add(elem); } #if NET_2_1 if (collectionType.IsArray) { Array array = Array.CreateInstance(elementType, c.Count); c.CopyTo(array, 0); ret = array; } else { ret = c; } #else ret = collectionType.IsArray ? ((ArrayList)c).ToArray(elementType) : c; #endif } else { if (collectionInstance == null) { collectionInstance = Activator.CreateInstance(collectionType); } MethodInfo add; if (collectionInstance.GetType().IsGenericType&& collectionInstance.GetType().GetGenericTypeDefinition() == typeof(LinkedList <>)) { add = collectionType.GetMethod("AddLast", new Type [] { elementType }); } else { add = collectionType.GetMethod("Add", new Type [] { elementType }); } if (add == null) { var icoll = typeof(ICollection <>).MakeGenericType(elementType); if (icoll.IsAssignableFrom(collectionInstance.GetType())) { add = icoll.GetMethod("Add"); } } if (add == null) { throw new MissingMethodException(elementType.FullName, "Add"); } for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent()) { if (!reader.IsStartElement("item")) { throw SerializationError(String.Format("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI)); } object element = ReadObject(elementType); add.Invoke(collectionInstance, new object [] { element }); } ret = collectionInstance; } reader.ReadEndElement(); return(ret); }
object DeserializeGenericCollection(Type collectionType, Type elementType) { reader.ReadStartElement(); object ret; if (collectionType.IsInterface) { collectionType = typeof(List <>).MakeGenericType(elementType); } if (TypeMap.IsDictionary(collectionType)) { object dic = Activator.CreateInstance(collectionType); var itemSetter = dic.GetType().GetProperty("Item"); var keyarr = new object [1]; for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent()) { if (!reader.IsStartElement("item")) { throw SerializationError(String.Format("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI)); } // reading a KeyValuePair in the form of <Key .../><Value .../> reader.Read(); reader.MoveToContent(); object key = ReadObject(elementType.GetGenericArguments() [0]); reader.MoveToContent(); object val = ReadObject(elementType.GetGenericArguments() [1]); reader.Read(); keyarr [0] = key; itemSetter.SetValue(dic, val, keyarr); } ret = dic; } else if (typeof(IList).IsAssignableFrom(collectionType)) { #if NET_2_1 Type listType = collectionType.IsArray ? typeof(List <>).MakeGenericType(elementType) : null; #else Type listType = collectionType.IsArray ? typeof(ArrayList) : null; #endif IList c = (IList)Activator.CreateInstance(listType ?? collectionType); for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent()) { if (!reader.IsStartElement("item")) { throw SerializationError(String.Format("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI)); } Type et = elementType == typeof(object) || elementType.IsAbstract ? null : elementType; object elem = ReadObject(et ?? typeof(object)); c.Add(elem); } #if NET_2_1 if (collectionType.IsArray) { Array array = Array.CreateInstance(elementType, c.Count); c.CopyTo(array, 0); ret = array; } else { ret = c; } #else ret = collectionType.IsArray ? ((ArrayList)c).ToArray(elementType) : c; #endif } else { object c = Activator.CreateInstance(collectionType); MethodInfo add = collectionType.GetMethod("Add", new Type [] { elementType }); if (add == null) { var icoll = typeof(ICollection <>).MakeGenericType(elementType); if (icoll.IsAssignableFrom(c.GetType())) { add = icoll.GetMethod("Add"); } } for (reader.MoveToContent(); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent()) { if (!reader.IsStartElement("item")) { throw SerializationError(String.Format("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI)); } object elem = ReadObject(elementType); add.Invoke(c, new object [] { elem }); } ret = c; } reader.ReadEndElement(); return(ret); }
public void WriteObjectContent(object graph, bool top, bool outputTypeName) { if (graph == null) { if (top) { GetTypeMap(root_type); // to make sure to reject invalid contracts } writer.WriteString(null); return; } if (serialized_object_count++ == serializer.MaxItemsInObjectGraph) { throw new SerializationException(String.Format("The object graph exceeded the maximum object count '{0}' specified in the serializer", serializer.MaxItemsInObjectGraph)); } switch (Type.GetTypeCode(graph.GetType())) { case TypeCode.Char: case TypeCode.String: writer.WriteString(graph.ToString()); break; case TypeCode.Single: case TypeCode.Double: writer.WriteAttributeString("type", "number"); writer.WriteString(((IFormattable)graph).ToString("R", CultureInfo.InvariantCulture)); break; case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Decimal: writer.WriteAttributeString("type", "number"); if (graph.GetType().IsEnum) { graph = ((IConvertible)graph).ToType(Enum.GetUnderlyingType(graph.GetType()), CultureInfo.InvariantCulture); } writer.WriteString(((IFormattable)graph).ToString("G", CultureInfo.InvariantCulture)); break; case TypeCode.Boolean: writer.WriteAttributeString("type", "boolean"); if ((bool)graph) { writer.WriteString("true"); } else { writer.WriteString("false"); } break; case TypeCode.DateTime: writer.WriteString(String.Format(CultureInfo.InvariantCulture, "/Date({0})/", (long)((DateTime)graph).Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds)); break; default: if (graph is Guid) { goto case TypeCode.String; } else if (graph is Uri) { goto case TypeCode.String; } else if (graph is XmlQualifiedName) { XmlQualifiedName qn = (XmlQualifiedName)graph; writer.WriteString(qn.Name); writer.WriteString(":"); writer.WriteString(qn.Namespace); } else if (graph is IDictionary) { writer.WriteAttributeString("type", "array"); IDictionary dic = (IDictionary)graph; foreach (object o in dic.Keys) { writer.WriteStartElement("item"); writer.WriteAttributeString("type", "object"); // outputting a KeyValuePair as <Key .. /><Value ... /> writer.WriteStartElement("Key"); WriteObjectContent(o, false, !(graph is Array && graph.GetType().GetElementType() != typeof(object))); writer.WriteEndElement(); writer.WriteStartElement("Value"); WriteObjectContent(dic[o], false, !(graph is Array && graph.GetType().GetElementType() != typeof(object))); writer.WriteEndElement(); writer.WriteEndElement(); } } else if (graph is ICollection) // array { writer.WriteAttributeString("type", "array"); foreach (object o in (ICollection)graph) { writer.WriteStartElement("item"); // when it is typed, then no need to output "__type" WriteObjectContent(o, false, !(graph is Array && graph.GetType().GetElementType() != typeof(object))); writer.WriteEndElement(); } } else // object { TypeMap tm = GetTypeMap(graph.GetType()); if (tm != null) { // FIXME: I'm not sure how it is determined whether __type is written or not... if (outputTypeName || always_emit_type) { writer.WriteAttributeString("__type", FormatTypeName(graph.GetType())); } tm.Serialize(this, graph, "object"); } else { // it does not emit type="object" (as the graph is regarded as a string) // writer.WriteString (graph.ToString ()); throw new InvalidDataContractException(String.Format("Type {0} cannot be serialized by this JSON serializer", graph.GetType())); } } break; } }