diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs index ed849b76284eee..88cdc8a5465add 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs @@ -246,163 +246,150 @@ private XmlQualifiedName GetPrimitiveTypeName(Type type) [RequiresUnreferencedCode(XmlSerializer.TrimSerializationWarning)] protected void WriteTypedPrimitive(string? name, string? ns, object o, bool xsiType) { - string? value; - string type; - string typeNs = XmlSchema.Namespace; - bool writeRaw = true; - bool writeDirect = false; - Type t = o.GetType(); - bool wroteStartElement = false; + void WriteFunc(T value, string lType, string lTypeNs = XmlSchema.Namespace) + { + if (name == null) + _w.WriteStartElement(lType, lTypeNs); + else + _w.WriteStartElement(name, ns); + if (xsiType) WriteXsiType(lType, lTypeNs); + + if (value == null) + { + _w.WriteAttributeString("nil", XmlSchema.InstanceNamespace, "true"); + } + else + { + if (typeof(T) == typeof(string)) + _w.WriteString((string?)(object?)value); + else if (typeof(T) == typeof(int)) + _w.WriteValue((int)(object)value); + else if (typeof(T) == typeof(bool)) + _w.WriteValue((bool)(object)value); + else if (typeof(T) == typeof(short)) + _w.WriteValue((short)(object)value); + else if (typeof(T) == typeof(long)) + _w.WriteValue((long)(object)value); + else if (typeof(T) == typeof(float)) + _w.WriteValue((float)(object)value); + else if (typeof(T) == typeof(double)) + _w.WriteValue((double)(object)value); + else if (typeof(T) == typeof(decimal)) + _w.WriteValue((decimal)(object)value); + else if (typeof(T) == typeof(byte)) + _w.WriteValue((byte)(object)value); + else if (typeof(T) == typeof(sbyte)) + _w.WriteValue((sbyte)(object)value); + else if (typeof(T) == typeof(ushort)) + _w.WriteValue((ushort)(object)value); + else if (typeof(T) == typeof(uint)) + _w.WriteValue((uint)(object)value); + //else if (typeof(T) == typeof(ulong)) + // _w.WriteValue((ulong)(object)value); + //else if (typeof(T) == typeof(Guid)) + // _w.WriteValue((Guid)(object)value); + else if (typeof(T) == typeof(TimeSpan)) + _w.WriteValue((TimeSpan)(object)value); + else if (typeof(T) == typeof(DateTimeOffset)) + _w.WriteValue((DateTimeOffset)(object)value); + else if (typeof(T) == typeof(byte[])) + XmlCustomFormatter.WriteArrayBase64(_w, (byte[])(object)value, 0, ((byte[])(object)value).Length); + else if (typeof(T) == typeof(XmlNode[])) + { + XmlNode[] xmlNodes = (XmlNode[])o; + for (int i = 0; i < xmlNodes.Length; i++) + { + if (xmlNodes[i] == null) + continue; + xmlNodes[i].WriteTo(_w); + } + } + else + throw CreateUnknownTypeException(typeof(T)); + } + + _w.WriteEndElement(); + } + Type t = o.GetType(); switch (Type.GetTypeCode(t)) { case TypeCode.String: - value = (string)o; - type = "string"; - writeRaw = false; + WriteFunc((string)o, "string"); break; case TypeCode.Int32: - value = XmlConvert.ToString((int)o); - type = "int"; + WriteFunc((int)o, "int"); break; case TypeCode.Boolean: - value = XmlConvert.ToString((bool)o); - type = "boolean"; + WriteFunc((bool)o, "boolean"); break; case TypeCode.Int16: - value = XmlConvert.ToString((short)o); - type = "short"; + WriteFunc((short)o, "short"); break; case TypeCode.Int64: - value = XmlConvert.ToString((long)o); - type = "long"; + WriteFunc((long)o, "long"); break; case TypeCode.Single: - value = XmlConvert.ToString((float)o); - type = "float"; + WriteFunc((float)o, "float"); break; case TypeCode.Double: - value = XmlConvert.ToString((double)o); - type = "double"; + WriteFunc((double)o, "double"); break; case TypeCode.Decimal: - value = XmlConvert.ToString((decimal)o); - type = "decimal"; + WriteFunc((decimal)o, "decimal"); break; case TypeCode.DateTime: - value = FromDateTime((DateTime)o); - type = "dateTime"; + WriteFunc(FromDateTime((DateTime)o), "dateTime"); break; case TypeCode.Char: - value = FromChar((char)o); - type = "char"; - typeNs = UrtTypes.Namespace; + WriteFunc((ushort)(char)o, "char", UrtTypes.Namespace); break; case TypeCode.Byte: - value = XmlConvert.ToString((byte)o); - type = "unsignedByte"; + WriteFunc((byte)o, "unsignedByte"); break; case TypeCode.SByte: - value = XmlConvert.ToString((sbyte)o); - type = "byte"; + WriteFunc((sbyte)o, "byte"); break; case TypeCode.UInt16: - value = XmlConvert.ToString((ushort)o); - type = "unsignedShort"; + WriteFunc((ushort)o, "unsignedShort"); break; case TypeCode.UInt32: - value = XmlConvert.ToString((uint)o); - type = "unsignedInt"; + WriteFunc((uint)o, "unsignedInt"); break; case TypeCode.UInt64: - value = XmlConvert.ToString((ulong)o); - type = "unsignedLong"; + WriteFunc(XmlConvert.ToString((ulong)o), "unsignedLong"); break; default: if (t == typeof(XmlQualifiedName)) { - type = "QName"; - // need to write start element ahead of time to establish context - // for ns definitions by FromXmlQualifiedName - wroteStartElement = true; - if (name == null) - _w.WriteStartElement(type, typeNs); - else - _w.WriteStartElement(name, ns); - value = FromXmlQualifiedName((XmlQualifiedName)o, false); + WriteFunc(FromXmlQualifiedName((XmlQualifiedName)o, false), "QName"); } else if (t == typeof(byte[])) { - value = string.Empty; - writeDirect = true; - type = "base64Binary"; + WriteFunc((byte[])o, "base64Binary"); } else if (t == typeof(Guid)) { - value = XmlConvert.ToString((Guid)o); - type = "guid"; - typeNs = UrtTypes.Namespace; + //WriteFunc((Guid)o); + WriteFunc(XmlConvert.ToString((Guid)o), "guid", UrtTypes.Namespace); } else if (t == typeof(TimeSpan)) { - value = XmlConvert.ToString((TimeSpan)o); - type = "TimeSpan"; - typeNs = UrtTypes.Namespace; + WriteFunc((TimeSpan)o, "TimeSpan", UrtTypes.Namespace); } else if (t == typeof(DateTimeOffset)) { - value = XmlConvert.ToString((DateTimeOffset)o); - type = "dateTimeOffset"; - typeNs = UrtTypes.Namespace; + WriteFunc((DateTimeOffset)o, "dateTimeOffset", UrtTypes.Namespace); } else if (typeof(XmlNode[]).IsAssignableFrom(t)) { - if (name == null) - _w.WriteStartElement(Soap.UrType, XmlSchema.Namespace); - else - _w.WriteStartElement(name, ns); - - XmlNode[] xmlNodes = (XmlNode[])o; - for (int i = 0; i < xmlNodes.Length; i++) - { - if (xmlNodes[i] == null) - continue; - xmlNodes[i].WriteTo(_w); - } - _w.WriteEndElement(); - return; + WriteFunc((XmlNode[])o, Soap.UrType); } else throw CreateUnknownTypeException(t); break; } - if (!wroteStartElement) - { - if (name == null) - _w.WriteStartElement(type, typeNs); - else - _w.WriteStartElement(name, ns); - } - - if (xsiType) WriteXsiType(type, typeNs); - - if (value == null) - { - _w.WriteAttributeString("nil", XmlSchema.InstanceNamespace, "true"); - } - else if (writeDirect) - { - // only one type currently writes directly to XML stream - XmlCustomFormatter.WriteArrayBase64(_w, (byte[])o, 0, ((byte[])o).Length); - } - else if (writeRaw) - { - _w.WriteRaw(value); - } - else - _w.WriteString(value); - _w.WriteEndElement(); } private string GetQualifiedName(string name, string? ns) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs index 1e74f8425a252c..724728fe7ee665 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs @@ -195,7 +195,7 @@ private void WritePrimitiveValue(TypeDesc typeDesc, SourceInfo source, out Type } [RequiresUnreferencedCode("Calls WriteCheckDefault")] - private void WritePrimitive(string method, string name, string? ns, object? defaultValue, SourceInfo source, TypeMapping mapping, bool writeXsiType, bool isElement, bool isNullable) + private void WritePrimitive(string method, string name, string? ns, object? defaultValue, SourceInfo source, TypeMapping mapping, bool isNullable) { TypeDesc typeDesc = mapping.TypeDesc!; bool hasDefault = defaultValue != null && defaultValue != DBNull.Value && mapping.TypeDesc!.HasDefaultSupport; @@ -252,20 +252,27 @@ private void WritePrimitive(string method, string name, string? ns, object? defa } else { - WritePrimitiveValue(typeDesc, source, out argType); - argTypes.Add(argType); - } - - if (writeXsiType) - { - argTypes.Add(typeof(XmlQualifiedName)); - ConstructorInfo XmlQualifiedName_ctor = typeof(XmlQualifiedName).GetConstructor( - CodeGenerator.InstanceBindingFlags, - new Type[] { typeof(string), typeof(string) } + if (!typeDesc.HasCustomFormatter && !(typeDesc == StringTypeDesc || typeDesc.FormatterName == "String")) + { + MethodInfo XmlSerializationWriter_WriteTypedPrimitive = typeof(XmlSerializationWriter).GetMethod( + "WriteTypedPrimitive", + CodeGenerator.InstanceBindingFlags, + new Type[] { typeof(string), typeof(string), typeof(object), typeof(bool) } )!; - ilg.Ldstr(GetCSharpString(mapping.TypeName)); - ilg.Ldstr(GetCSharpString(mapping.Namespace)); - ilg.New(XmlQualifiedName_ctor); + source.Load(typeof(object)); + ilg.Ldc(false); + ilg.Call(XmlSerializationWriter_WriteTypedPrimitive); + if (hasDefault) + { + ilg.EndIf(); + } + return; + } + else + { + WritePrimitiveValue(typeDesc, source, out argType); + argTypes.Add(argType); + } } MethodInfo XmlSerializationWriter_method = typeof(XmlSerializationWriter).GetMethod( @@ -1391,7 +1398,7 @@ private void WriteAttribute(SourceInfo source, AttributeAccessor attribute, stri { TypeDesc typeDesc = attribute.Mapping!.TypeDesc!; source = source.CastTo(typeDesc); - WritePrimitive("WriteAttribute", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "", GetConvertedDefaultValue(source.Type, attribute.Default), source, attribute.Mapping, false, false, false); + WritePrimitive("WriteAttribute", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "", GetConvertedDefaultValue(source.Type, attribute.Default), source, attribute.Mapping, false); } } @@ -1990,7 +1997,7 @@ private void WriteElement(SourceInfo source, ElementAccessor element, string arr } else if (element.Mapping is EnumMapping) { - WritePrimitive("WriteElementString", name, ns, element.Default, source, element.Mapping, false, true, element.IsNullable); + WritePrimitive("WriteElementString", name, ns, element.Default, source, element.Mapping, element.IsNullable); } else if (element.Mapping is PrimitiveMapping primitiveMapping) { @@ -2002,7 +2009,7 @@ private void WriteElement(SourceInfo source, ElementAccessor element, string arr { string suffixRaw = primitiveMapping.TypeDesc!.XmlEncodingNotRequired ? "Raw" : ""; WritePrimitive(element.IsNullable ? ("WriteNullableStringLiteral" + suffixRaw) : ("WriteElementString" + suffixRaw), - name, ns, GetConvertedDefaultValue(source.Type, element.Default), source, primitiveMapping, false, true, element.IsNullable); + name, ns, GetConvertedDefaultValue(source.Type, element.Default), source, primitiveMapping, element.IsNullable); } } else if (element.Mapping is StructMapping structMapping)