diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 38006af94d6..4eb94e9ba34 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -1822,44 +1822,49 @@ private MethodBodyStatement CreateValueSerializationStatement( SerializationFormat serializationFormat, ValueExpression value) { - // append the `.Value` if needed (when the type is nullable and a value type) - value = value.NullableStructValue(type); - - // now we just need to focus on how we serialize a value - if (type.IsFrameworkType) - return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type.FrameworkType, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat); - - if (!type.IsEnum) - return _utf8JsonWriterSnippet.WriteObjectValue(value.As(type), options: _mrwOptionsParameterSnippet); - - if (type.IsStruct) //is extensible - { - if (type.UnderlyingEnumType.Equals(typeof(string))) - return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke(nameof(ToString))); - - return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}")); - } - else - { - if (type.UnderlyingEnumType.Equals(typeof(int))) - // when the fixed enum is implemented as int, we cast to the value - return _utf8JsonWriterSnippet.WriteNumberValue(value.CastTo(type.UnderlyingEnumType)); - - if (type.UnderlyingEnumType.Equals(typeof(string))) - return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}")); - - return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}")); - } + return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat); } internal static MethodBodyStatement SerializeJsonValueCore( - Type valueType, + CSharpType valueType, ValueExpression value, ScopedApi utf8JsonWriter, ScopedApi mrwOptionsParameter, SerializationFormat serializationFormat) { - MethodBodyStatement? statement = valueType switch + // append the `.Value` if needed (when the type is nullable and a value type) + value = value.NullableStructValue(valueType); + + // Handle enums + if (valueType.IsEnum) + { + if (valueType.IsStruct) // extensible enum + { + if (valueType.UnderlyingEnumType.Equals(typeof(string))) + return utf8JsonWriter.WriteStringValue(value.Invoke(nameof(ToString))); + + return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}")); + } + else // fixed enum + { + if (valueType.UnderlyingEnumType.Equals(typeof(int))) + // when the fixed enum is implemented as int, we cast to the value + return utf8JsonWriter.WriteNumberValue(value.CastTo(valueType.UnderlyingEnumType)); + + if (valueType.UnderlyingEnumType.Equals(typeof(string))) + return utf8JsonWriter.WriteStringValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}")); + + return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}")); + } + } + + // Handle non-enum types + if (!valueType.IsFrameworkType) + return utf8JsonWriter.WriteObjectValue(value.As(valueType), options: mrwOptionsParameter); + + // Handle framework types + var frameworkType = valueType.FrameworkType; + MethodBodyStatement? statement = frameworkType switch { var t when t == typeof(JsonElement) => value.As().WriteTo(utf8JsonWriter), @@ -1868,7 +1873,7 @@ var t when ValueTypeIsInt(t) && serializationFormat == SerializationFormat.Int_S var t when ValueTypeIsNumber(t) => utf8JsonWriter.WriteNumberValue(value), var t when t == typeof(object) => - utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter), + utf8JsonWriter.WriteObjectValue(value.As(frameworkType), mrwOptionsParameter), var t when t == typeof(string) || t == typeof(char) || t == typeof(Guid) => utf8JsonWriter.WriteStringValue(value), var t when t == typeof(bool) => @@ -1876,13 +1881,13 @@ var t when ValueTypeIsNumber(t) => var t when t == typeof(byte[]) => utf8JsonWriter.WriteBase64StringValue(value, serializationFormat.ToFormatSpecifier()), var t when t == typeof(DateTimeOffset) || t == typeof(DateTime) || t == typeof(TimeSpan) => - SerializeDateTimeRelatedTypes(valueType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter), + SerializeDateTimeRelatedTypes(frameworkType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter), var t when t == typeof(IPAddress) => utf8JsonWriter.WriteStringValue(value.InvokeToString()), var t when t == typeof(Uri) => utf8JsonWriter.WriteStringValue(new MemberExpression(value, nameof(Uri.AbsoluteUri))), var t when t == typeof(BinaryData) => - SerializeBinaryData(valueType, serializationFormat, value, utf8JsonWriter), + SerializeBinaryData(frameworkType, serializationFormat, value, utf8JsonWriter), var t when t == typeof(Stream) => utf8JsonWriter.WriteBinaryData(BinaryDataSnippets.FromStream(value, false)), _ => null @@ -1894,7 +1899,6 @@ var t when ValueTypeIsNumber(t) => DiagnosticCodes.UnsupportedSerialization, $"Serialization of type {valueType.Name} is not supported.", severity: EmitterDiagnosticSeverity.Warning); - return utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter); } @@ -1902,16 +1906,42 @@ var t when ValueTypeIsNumber(t) => } internal static ValueExpression DeserializeJsonValueCore( - Type valueType, + CSharpType valueType, ScopedApi element, ScopedApi data, ScopedApi mrwOptions, SerializationFormat format) { - ValueExpression? exp = valueType switch + // Handle enums + if (valueType.IsEnum) + { + var underlyingValue = DeserializeJsonValueCore( + new CSharpType(valueType.UnderlyingEnumType!), + element, + data, + mrwOptions, + format); + return valueType.ToEnum(underlyingValue); + } + + // Handle nullable types + if (valueType.IsFrameworkType && valueType.FrameworkType == typeof(Nullable<>)) + { + return DeserializeJsonValueCore(valueType.Arguments[0], element, data, mrwOptions, format); + } + + // Handle non-framework types + if (!valueType.IsFrameworkType) + { + return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions); + } + + // Handle framework types + var frameworkType = valueType.FrameworkType; + ValueExpression? exp = frameworkType switch { Type t when t == typeof(Uri) => - New.Instance(valueType, element.GetString()), + New.Instance(frameworkType, element.GetString()), Type t when t == typeof(IPAddress) => Static().Invoke(nameof(IPAddress.Parse), element.GetString()), Type t when t == typeof(BinaryData) => @@ -1965,7 +1995,7 @@ Type t when ValueTypeIsInt(t) => DiagnosticCodes.UnsupportedSerialization, $"Deserialization of type {valueType.Name} is not supported.", severity: EmitterDiagnosticSeverity.Warning); - return GetDeserializationMethodInvocationForType(new CSharpType(valueType), element, data, mrwOptions); + return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions); } return exp; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs index 13cc6d86e7f..de4cb276c3e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs @@ -230,7 +230,7 @@ private ExtensibleEnumSerializationProvider[] CreateExtensibleEnumSerializations } public virtual ValueExpression DeserializeJsonValue( - Type valueType, + CSharpType valueType, ScopedApi element, ScopedApi data, ScopedApi mrwOptionsParameter, @@ -238,7 +238,7 @@ public virtual ValueExpression DeserializeJsonValue( => MrwSerializationTypeDefinition.DeserializeJsonValueCore(valueType, element, data, mrwOptionsParameter, format); public virtual MethodBodyStatement SerializeJsonValue( - Type valueType, + CSharpType valueType, ValueExpression value, ScopedApi utf8JsonWriter, ScopedApi mrwOptionsParameter,