Skip to content

Commit ec260f5

Browse files
Use CSharpType rather than Type for serialization hooks (#9166)
For framework types that are generic where the arg may be a non-framework type, we lose the generic type arg information when using Type.
1 parent 6439e09 commit ec260f5

File tree

2 files changed

+70
-40
lines changed

2 files changed

+70
-40
lines changed

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,44 +1822,49 @@ private MethodBodyStatement CreateValueSerializationStatement(
18221822
SerializationFormat serializationFormat,
18231823
ValueExpression value)
18241824
{
1825-
// append the `.Value` if needed (when the type is nullable and a value type)
1826-
value = value.NullableStructValue(type);
1827-
1828-
// now we just need to focus on how we serialize a value
1829-
if (type.IsFrameworkType)
1830-
return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type.FrameworkType, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat);
1831-
1832-
if (!type.IsEnum)
1833-
return _utf8JsonWriterSnippet.WriteObjectValue(value.As(type), options: _mrwOptionsParameterSnippet);
1834-
1835-
if (type.IsStruct) //is extensible
1836-
{
1837-
if (type.UnderlyingEnumType.Equals(typeof(string)))
1838-
return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke(nameof(ToString)));
1839-
1840-
return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}"));
1841-
}
1842-
else
1843-
{
1844-
if (type.UnderlyingEnumType.Equals(typeof(int)))
1845-
// when the fixed enum is implemented as int, we cast to the value
1846-
return _utf8JsonWriterSnippet.WriteNumberValue(value.CastTo(type.UnderlyingEnumType));
1847-
1848-
if (type.UnderlyingEnumType.Equals(typeof(string)))
1849-
return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}"));
1850-
1851-
return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}"));
1852-
}
1825+
return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat);
18531826
}
18541827

18551828
internal static MethodBodyStatement SerializeJsonValueCore(
1856-
Type valueType,
1829+
CSharpType valueType,
18571830
ValueExpression value,
18581831
ScopedApi<Utf8JsonWriter> utf8JsonWriter,
18591832
ScopedApi<ModelReaderWriterOptions> mrwOptionsParameter,
18601833
SerializationFormat serializationFormat)
18611834
{
1862-
MethodBodyStatement? statement = valueType switch
1835+
// append the `.Value` if needed (when the type is nullable and a value type)
1836+
value = value.NullableStructValue(valueType);
1837+
1838+
// Handle enums
1839+
if (valueType.IsEnum)
1840+
{
1841+
if (valueType.IsStruct) // extensible enum
1842+
{
1843+
if (valueType.UnderlyingEnumType.Equals(typeof(string)))
1844+
return utf8JsonWriter.WriteStringValue(value.Invoke(nameof(ToString)));
1845+
1846+
return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}"));
1847+
}
1848+
else // fixed enum
1849+
{
1850+
if (valueType.UnderlyingEnumType.Equals(typeof(int)))
1851+
// when the fixed enum is implemented as int, we cast to the value
1852+
return utf8JsonWriter.WriteNumberValue(value.CastTo(valueType.UnderlyingEnumType));
1853+
1854+
if (valueType.UnderlyingEnumType.Equals(typeof(string)))
1855+
return utf8JsonWriter.WriteStringValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}"));
1856+
1857+
return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}"));
1858+
}
1859+
}
1860+
1861+
// Handle non-enum types
1862+
if (!valueType.IsFrameworkType)
1863+
return utf8JsonWriter.WriteObjectValue(value.As(valueType), options: mrwOptionsParameter);
1864+
1865+
// Handle framework types
1866+
var frameworkType = valueType.FrameworkType;
1867+
MethodBodyStatement? statement = frameworkType switch
18631868
{
18641869
var t when t == typeof(JsonElement) =>
18651870
value.As<JsonElement>().WriteTo(utf8JsonWriter),
@@ -1868,21 +1873,21 @@ var t when ValueTypeIsInt(t) && serializationFormat == SerializationFormat.Int_S
18681873
var t when ValueTypeIsNumber(t) =>
18691874
utf8JsonWriter.WriteNumberValue(value),
18701875
var t when t == typeof(object) =>
1871-
utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter),
1876+
utf8JsonWriter.WriteObjectValue(value.As(frameworkType), mrwOptionsParameter),
18721877
var t when t == typeof(string) || t == typeof(char) || t == typeof(Guid) =>
18731878
utf8JsonWriter.WriteStringValue(value),
18741879
var t when t == typeof(bool) =>
18751880
utf8JsonWriter.WriteBooleanValue(value),
18761881
var t when t == typeof(byte[]) =>
18771882
utf8JsonWriter.WriteBase64StringValue(value, serializationFormat.ToFormatSpecifier()),
18781883
var t when t == typeof(DateTimeOffset) || t == typeof(DateTime) || t == typeof(TimeSpan) =>
1879-
SerializeDateTimeRelatedTypes(valueType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter),
1884+
SerializeDateTimeRelatedTypes(frameworkType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter),
18801885
var t when t == typeof(IPAddress) =>
18811886
utf8JsonWriter.WriteStringValue(value.InvokeToString()),
18821887
var t when t == typeof(Uri) =>
18831888
utf8JsonWriter.WriteStringValue(new MemberExpression(value, nameof(Uri.AbsoluteUri))),
18841889
var t when t == typeof(BinaryData) =>
1885-
SerializeBinaryData(valueType, serializationFormat, value, utf8JsonWriter),
1890+
SerializeBinaryData(frameworkType, serializationFormat, value, utf8JsonWriter),
18861891
var t when t == typeof(Stream) =>
18871892
utf8JsonWriter.WriteBinaryData(BinaryDataSnippets.FromStream(value, false)),
18881893
_ => null
@@ -1894,24 +1899,49 @@ var t when ValueTypeIsNumber(t) =>
18941899
DiagnosticCodes.UnsupportedSerialization,
18951900
$"Serialization of type {valueType.Name} is not supported.",
18961901
severity: EmitterDiagnosticSeverity.Warning);
1897-
18981902
return utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter);
18991903
}
19001904

19011905
return statement;
19021906
}
19031907

19041908
internal static ValueExpression DeserializeJsonValueCore(
1905-
Type valueType,
1909+
CSharpType valueType,
19061910
ScopedApi<JsonElement> element,
19071911
ScopedApi<BinaryData> data,
19081912
ScopedApi<ModelReaderWriterOptions> mrwOptions,
19091913
SerializationFormat format)
19101914
{
1911-
ValueExpression? exp = valueType switch
1915+
// Handle enums
1916+
if (valueType.IsEnum)
1917+
{
1918+
var underlyingValue = DeserializeJsonValueCore(
1919+
new CSharpType(valueType.UnderlyingEnumType!),
1920+
element,
1921+
data,
1922+
mrwOptions,
1923+
format);
1924+
return valueType.ToEnum(underlyingValue);
1925+
}
1926+
1927+
// Handle nullable types
1928+
if (valueType.IsFrameworkType && valueType.FrameworkType == typeof(Nullable<>))
1929+
{
1930+
return DeserializeJsonValueCore(valueType.Arguments[0], element, data, mrwOptions, format);
1931+
}
1932+
1933+
// Handle non-framework types
1934+
if (!valueType.IsFrameworkType)
1935+
{
1936+
return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions);
1937+
}
1938+
1939+
// Handle framework types
1940+
var frameworkType = valueType.FrameworkType;
1941+
ValueExpression? exp = frameworkType switch
19121942
{
19131943
Type t when t == typeof(Uri) =>
1914-
New.Instance(valueType, element.GetString()),
1944+
New.Instance(frameworkType, element.GetString()),
19151945
Type t when t == typeof(IPAddress) =>
19161946
Static<IPAddress>().Invoke(nameof(IPAddress.Parse), element.GetString()),
19171947
Type t when t == typeof(BinaryData) =>
@@ -1965,7 +1995,7 @@ Type t when ValueTypeIsInt(t) =>
19651995
DiagnosticCodes.UnsupportedSerialization,
19661996
$"Deserialization of type {valueType.Name} is not supported.",
19671997
severity: EmitterDiagnosticSeverity.Warning);
1968-
return GetDeserializationMethodInvocationForType(new CSharpType(valueType), element, data, mrwOptions);
1998+
return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions);
19691999
}
19702000

19712001
return exp;

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,15 @@ private ExtensibleEnumSerializationProvider[] CreateExtensibleEnumSerializations
230230
}
231231

232232
public virtual ValueExpression DeserializeJsonValue(
233-
Type valueType,
233+
CSharpType valueType,
234234
ScopedApi<JsonElement> element,
235235
ScopedApi<BinaryData> data,
236236
ScopedApi<ModelReaderWriterOptions> mrwOptionsParameter,
237237
SerializationFormat format)
238238
=> MrwSerializationTypeDefinition.DeserializeJsonValueCore(valueType, element, data, mrwOptionsParameter, format);
239239

240240
public virtual MethodBodyStatement SerializeJsonValue(
241-
Type valueType,
241+
CSharpType valueType,
242242
ValueExpression value,
243243
ScopedApi<Utf8JsonWriter> utf8JsonWriter,
244244
ScopedApi<ModelReaderWriterOptions> mrwOptionsParameter,

0 commit comments

Comments
 (0)