From 1d43455d2873df6bae930ed210d8c61ff90206cb Mon Sep 17 00:00:00 2001
From: Nisha Bhatia <67986960+nisha-bhatia@users.noreply.github.com>
Date: Tue, 30 Jul 2024 15:58:51 -0700
Subject: [PATCH] Move ToSerial and ToEnum to SerializationProviders (#3795)
Fixes: [#3651](https://github.com/microsoft/typespec/issues/3651)
---------
Co-authored-by: m-nash <64171366+m-nash@users.noreply.github.com>
Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com>
---
.../ExtensibleEnumSerializationProvider.cs | 66 ++++++++++
.../FixedEnumSerializationProvider.cs | 61 +++++----
.../src/ScmTypeFactory.cs | 10 ++
....Generator.CSharp.ClientModel.Tests.csproj | 1 -
.../EnumProviderSerializationTests.cs | 62 ++++++++++
.../src/Primitives/CSharpType.cs | 2 +-
.../src/Providers/EnumProvider.cs | 48 +++----
.../src/Providers/ExtensibleEnumProvider.cs | 57 +++------
.../src/Providers/FixedEnumProvider.cs | 31 ++---
.../src/Providers/TypeProvider.cs | 12 ++
.../src/Snippets/Snippet.New.cs | 8 +-
.../src/TypeFactory.cs | 9 --
.../test/Providers/EnumProviderTests.cs | 117 ------------------
...questOptionalLiteralFloat.Serialization.cs | 12 ++
...nonymousBodyRequestOptionalLiteralFloat.cs | 2 -
...RequestOptionalLiteralInt.Serialization.cs | 12 ++
.../AnonymousBodyRequestOptionalLiteralInt.cs | 2 -
...questRequiredLiteralFloat.Serialization.cs | 12 ++
...nonymousBodyRequestRequiredLiteralFloat.cs | 2 -
...RequestRequiredLiteralInt.Serialization.cs | 12 ++
.../AnonymousBodyRequestRequiredLiteralInt.cs | 2 -
.../FloatExtensibleEnum.Serialization.cs | 12 ++
.../Generated/Models/FloatExtensibleEnum.cs | 2 -
...xtensibleEnumWithIntValue.Serialization.cs | 12 ++
.../Models/FloatExtensibleEnumWithIntValue.cs | 2 -
...ons.cs => FloatFixedEnum.Serialization.cs} | 0
...oatFixedEnumWithIntValue.Serialization.cs} | 0
.../Models/IntExtensibleEnum.Serialization.cs | 12 ++
.../src/Generated/Models/IntExtensibleEnum.cs | 2 -
...sions.cs => IntFixedEnum.Serialization.cs} | 0
...ns.cs => StringFixedEnum.Serialization.cs} | 0
...ThingOptionalLiteralFloat.Serialization.cs | 12 ++
.../Models/ThingOptionalLiteralFloat.cs | 2 -
.../ThingOptionalLiteralInt.Serialization.cs | 12 ++
.../Models/ThingOptionalLiteralInt.cs | 2 -
...ThingRequiredLiteralFloat.Serialization.cs | 12 ++
.../Models/ThingRequiredLiteralFloat.cs | 2 -
.../ThingRequiredLiteralInt.Serialization.cs | 12 ++
.../Models/ThingRequiredLiteralInt.cs | 2 -
39 files changed, 371 insertions(+), 267 deletions(-)
create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs
rename packages/http-client-csharp/generator/{Microsoft.Generator.CSharp => Microsoft.Generator.CSharp.ClientModel}/src/Providers/FixedEnumSerializationProvider.cs (67%)
create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/EnumProviderSerializationTests.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.Serialization.cs
rename packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/{FloatFixedEnumExtensions.cs => FloatFixedEnum.Serialization.cs} (100%)
rename packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/{FloatFixedEnumWithIntValueExtensions.cs => FloatFixedEnumWithIntValue.Serialization.cs} (100%)
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.Serialization.cs
rename packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/{IntFixedEnumExtensions.cs => IntFixedEnum.Serialization.cs} (100%)
rename packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/{StringFixedEnumExtensions.cs => StringFixedEnum.Serialization.cs} (100%)
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.Serialization.cs
create mode 100644 packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.Serialization.cs
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs
new file mode 100644
index 0000000000..4f2a880bf5
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs
@@ -0,0 +1,66 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using Microsoft.Generator.CSharp.Input;
+using Microsoft.Generator.CSharp.Primitives;
+using Microsoft.Generator.CSharp.Providers;
+
+namespace Microsoft.Generator.CSharp.ClientModel.Providers
+{
+ ///
+ /// This defines a class with extension methods for enums to convert an enum to its underlying value, or from its underlying value to an instance of the enum
+ ///
+ internal partial class ExtensibleEnumSerializationProvider : TypeProvider
+ {
+ private readonly InputEnumType _enumType;
+ private TypeProvider _enumProvider;
+
+ protected override string GetNamespace() => _enumProvider.Type.Namespace;
+
+ public ExtensibleEnumSerializationProvider(InputEnumType enumType)
+ {
+ Debug.Assert(enumType.IsExtensible);
+ _enumType = enumType;
+ _enumProvider = ClientModelPlugin.Instance.TypeFactory.CreateEnum(_enumType);
+ }
+
+ protected override string BuildRelativeFilePath()
+ {
+ return Path.Combine("src", "Generated", "Models", $"{_enumProvider.Name}.Serialization.cs");
+ }
+
+ protected override string BuildName() => _enumProvider.Name;
+
+ protected override TypeSignatureModifiers GetDeclarationModifiers() => _enumProvider.DeclarationModifiers;
+
+ protected override MethodProvider[] BuildMethods()
+ {
+ // for string-based extensible enums, we are using `ToString` as its serialization
+ // for non-string-based extensible enums, we need a method to serialize them
+ if (!_enumProvider.EnumUnderlyingType.Equals(typeof(string)))
+ {
+ var toSerialSignature = new MethodSignature(
+ Name: $"ToSerial{_enumProvider.EnumUnderlyingType.Name}",
+ Modifiers: MethodSignatureModifiers.Internal,
+ ReturnType: _enumProvider.EnumUnderlyingType,
+ Parameters: Array.Empty(),
+ Description: null,
+ ReturnDescription: null);
+
+ // writes the method:
+ // internal float ToSerialSingle() => _value; // when ValueType is float
+ // internal int ToSerialInt32() => _value; // when ValueType is int
+ // etc
+ var valueField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, _enumProvider.EnumUnderlyingType, "_value");
+ return [new MethodProvider(toSerialSignature, valueField, this)];
+ }
+ else
+ {
+ return Array.Empty();
+ }
+ }
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/FixedEnumSerializationProvider.cs
similarity index 67%
rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs
rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/FixedEnumSerializationProvider.cs
index 77d7bc1288..928951b3ea 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumSerializationProvider.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/FixedEnumSerializationProvider.cs
@@ -7,34 +7,40 @@
using System.IO;
using System.Linq;
using Microsoft.Generator.CSharp.Expressions;
+using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
+using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Snippets;
using Microsoft.Generator.CSharp.Statements;
using static Microsoft.Generator.CSharp.Snippets.Snippet;
-namespace Microsoft.Generator.CSharp.Providers
+namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
///
/// This defines a class with extension methods for enums to convert an enum to its underlying value, or from its underlying value to an instance of the enum
///
internal class FixedEnumSerializationProvider : TypeProvider
{
- private readonly EnumProvider _enumType;
+ private readonly InputEnumType _enumType;
+ private TypeProvider _enumProvider;
- public FixedEnumSerializationProvider(EnumProvider enumType)
+ public FixedEnumSerializationProvider(InputEnumType enumType)
{
Debug.Assert(!enumType.IsExtensible);
-
_enumType = enumType;
+ _enumProvider = ClientModelPlugin.Instance.TypeFactory.CreateEnum(_enumType);
}
- protected override string GetNamespace() => _enumType.Type.Namespace;
-
- protected override TypeSignatureModifiers GetDeclarationModifiers() => TypeSignatureModifiers.Internal | TypeSignatureModifiers.Static | TypeSignatureModifiers.Partial;
+ protected override string GetNamespace() => _enumProvider.Type.Namespace;
+ protected override TypeSignatureModifiers GetDeclarationModifiers()
+ => TypeSignatureModifiers.Internal | TypeSignatureModifiers.Static | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class;
- protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Models", $"{Name}.cs");
+ protected override string BuildRelativeFilePath()
+ {
+ return Path.Combine("src", "Generated", "Models", $"{_enumProvider.Name}.Serialization.cs");
+ }
- protected override string BuildName() => $"{_enumType.Name}Extensions";
+ protected override string BuildName() => $"{_enumProvider.Name}Extensions";
///
/// Returns if this enum type needs an extension method for serialization
@@ -43,7 +49,8 @@ public FixedEnumSerializationProvider(EnumProvider enumType)
private bool NeedsSerializationMethod()
{
// fixed enum with int based types, we do not write a method for serialization because it was embedded in the definition
- if (_enumType is { IsExtensible: false, IsIntValueType: true })
+ bool isIntValueType = _enumProvider.EnumUnderlyingType.Equals(typeof(int)) || _enumProvider.EnumUnderlyingType.Equals(typeof(long));
+ if (!_enumType.IsExtensible && isIntValueType)
return false;
// otherwise we need a serialization method with the name of `ToSerial{UnderlyingTypeName}`
@@ -56,32 +63,32 @@ protected override MethodProvider[] BuildMethods()
// serialization method (in some cases we do not need serialization)
if (NeedsSerializationMethod())
{
- var serializationValueParameter = new ParameterProvider("value", $"The value to serialize.", _enumType.Type);
+ var serializationValueParameter = new ParameterProvider("value", $"The value to serialize.", _enumProvider.Type);
var serializationSignature = new MethodSignature(
- Name: $"ToSerial{_enumType.ValueType.Name}",
+ Name: $"ToSerial{_enumProvider.EnumUnderlyingType.Name}",
Modifiers: MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Extension,
- ReturnType: _enumType.ValueType,
+ ReturnType: _enumProvider.EnumUnderlyingType,
Parameters: [serializationValueParameter],
Description: null, ReturnDescription: null);
// the fields of an enum type are the values of the enum type
- var knownCases = new SwitchCaseExpression[_enumType.Members.Count];
+ var knownCases = new SwitchCaseExpression[_enumProvider.EnumValues.Count];
for (int i = 0; i < knownCases.Length; i++)
{
- var enumValue = _enumType.Members[i];
- knownCases[i] = new SwitchCaseExpression(new MemberExpression(_enumType.Type, enumValue.Field.Name), Literal(enumValue.Value));
+ var enumValue = _enumProvider.EnumValues[i];
+ knownCases[i] = new SwitchCaseExpression(new MemberExpression(_enumProvider.Type, enumValue.Field.Name), Literal(enumValue.Value));
}
- var defaultCase = SwitchCaseExpression.Default(ThrowExpression(New.ArgumentOutOfRangeException(_enumType, serializationValueParameter)));
+ var defaultCase = SwitchCaseExpression.Default(ThrowExpression(New.ArgumentOutOfRangeException(_enumProvider, serializationValueParameter)));
var serializationBody = new SwitchExpression(serializationValueParameter, [.. knownCases, defaultCase]);
methods.Add(new(serializationSignature, serializationBody, this));
}
// deserialization method (we always need a deserialization)
- var deserializationValueParameter = new ParameterProvider("value", $"The value to deserialize.", _enumType.ValueType);
+ var deserializationValueParameter = new ParameterProvider("value", $"The value to deserialize.", _enumProvider.EnumUnderlyingType);
var deserializationSignature = new MethodSignature(
- Name: $"To{_enumType.Type.Name}",
+ Name: $"To{_enumProvider.Name}",
Modifiers: MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Extension,
- ReturnType: _enumType.Type,
+ ReturnType: _enumProvider.Type,
Parameters: [deserializationValueParameter],
Description: null, ReturnDescription: null);
@@ -92,12 +99,12 @@ protected override MethodProvider[] BuildMethods()
// in general, this loop builds up if statements for each value, it looks like:
// if () { return EnumType.TheValue; }
// the condition could be different depending on the type of the underlying value type of the enum
- for (int i = 0; i < _enumType.Fields.Count; i++)
+ for (int i = 0; i < _enumProvider.Fields.Count; i++)
{
- var enumField = _enumType.Fields[i];
- var enumValue = _enumType.Members[i];
+ var enumField = _enumProvider.Fields[i];
+ var enumValue = _enumProvider.EnumValues[i];
ScopedApi condition;
- if (_enumType.IsStringValueType)
+ if (_enumProvider.EnumUnderlyingType.Equals(typeof(string)))
{
// when the values are strings, we compare them case-insensitively
// this is either
@@ -106,7 +113,7 @@ protected override MethodProvider[] BuildMethods()
// string.Equals(value, "", StringComparison.InvariantCultureIgnoreCase)
condition = (enumValue.Value is string strValue && strValue.All(char.IsAscii)
? stringComparer.Invoke(nameof(IEqualityComparer.Equals), value, Literal(strValue))
- : Static(_enumType.ValueType).Invoke(nameof(Equals), [value, Literal(enumValue.Value), FrameworkEnumValue(StringComparison.InvariantCultureIgnoreCase)]))
+ : Static(_enumProvider.EnumUnderlyingType).Invoke(nameof(Equals), [value, Literal(enumValue.Value), FrameworkEnumValue(StringComparison.InvariantCultureIgnoreCase)]))
.As();
}
else
@@ -116,12 +123,12 @@ protected override MethodProvider[] BuildMethods()
}
deserializationBody.Add(new IfStatement(condition)
{
- Return(new MemberExpression(_enumType.Type, enumField.Name))
+ Return(new MemberExpression(_enumProvider.Type, enumField.Name))
});
}
// add a fallback throw statement to ensure every path of this method returns a value
- deserializationBody.Add(Throw(New.ArgumentOutOfRangeException(_enumType, deserializationValueParameter)));
+ deserializationBody.Add(Throw(New.ArgumentOutOfRangeException(_enumProvider, deserializationValueParameter)));
methods.Add(new(deserializationSignature, deserializationBody, this));
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs
index bdd132e101..0856bf4d60 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
@@ -38,6 +40,14 @@ protected override IReadOnlyList CreateSerializationsCore(InputTyp
{
case InputModelType inputModel when inputModel.Usage.HasFlag(InputModelTypeUsage.Json):
return [new MrwSerializationTypeDefinition(inputModel)];
+ case InputEnumType inputEnumType when inputEnumType.IsExtensible:
+ if (ClientModelPlugin.Instance.TypeFactory.CreateCSharpType(inputEnumType).UnderlyingEnumType.Equals(typeof(string)))
+ {
+ return [];
+ }
+ return [new ExtensibleEnumSerializationProvider(inputEnumType)];
+ case InputEnumType inputEnumType:
+ return [new FixedEnumSerializationProvider(inputEnumType)];
default:
return base.CreateSerializationsCore(inputType);
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj
index a78947f335..27196b77d5 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Microsoft.Generator.CSharp.ClientModel.Tests.csproj
@@ -24,5 +24,4 @@
PreserveNewest
-
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/EnumProviderSerializationTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/EnumProviderSerializationTests.cs
new file mode 100644
index 0000000000..7d38fcab66
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/EnumProviderSerializationTests.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Generator.CSharp.Expressions;
+using Microsoft.Generator.CSharp.Input;
+using Microsoft.Generator.CSharp.Providers;
+using Microsoft.Generator.CSharp.Statements;
+using NUnit.Framework;
+
+namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers
+{
+ public class EnumProviderSerializationTests
+ {
+ [OneTimeSetUp]
+ public void Setup()
+ {
+ MockHelpers.LoadMockPlugin();
+ }
+
+ public static object[] ValidateTestCases =
+ {
+ new object[] {"One", 1, "Two", 2}
+ };
+
+ private TypeProvider? CreateEnumSerializationProvider(string stringA, int intA, string stringB, int intB)
+ {
+ IReadOnlyList values = new List
+ {
+ new InputEnumTypeValue(stringA, intA, null),
+ new InputEnumTypeValue(stringB, intB, null)
+ };
+ var input = new InputEnumType("mockInputEnum", "mockNamespace", "public", null, "The mock enum", InputModelTypeUsage.Input | InputModelTypeUsage.Output, new InputPrimitiveType(InputPrimitiveTypeKind.Int32), values, false);
+ TypeProvider enumType = ClientModelPlugin.Instance.TypeFactory.CreateEnum(input);
+ return enumType.SerializationProviders.FirstOrDefault();
+ }
+
+ [TestCaseSource(nameof(ValidateTestCases))]
+ public void ValidateToSerial(string stringA, int intA, string stringB, int intB)
+ {
+ var serialization = CreateEnumSerializationProvider(stringA, intA, stringB, intB);
+ MethodProvider? method = serialization!.Methods.Where(m => m.Signature.Name.Contains("ToSerial")).FirstOrDefault();
+ // Cast method.BodyExpression to SwitchCaseExpression
+ Assert.IsNull(method);
+ }
+
+ [TestCaseSource(nameof(ValidateTestCases))]
+ public void ValidateToEnum(string stringA, int intA, string stringB, int intB)
+ {
+ var serialization = CreateEnumSerializationProvider(stringA, intA, stringB, intB);
+ MethodProvider? method = serialization!.Methods.Where(m => m.Signature.Name.Contains("Enum")).FirstOrDefault();
+ // Cast method.BodyExpression to SwitchCaseExpression
+ if (method!.BodyStatements is MethodBodyStatements methodBodyStatements)
+ {
+ // Verify that the switch case expression has the correct number of cases (values + 1 for throw)
+ Assert.AreEqual(3, methodBodyStatements.Statements.Count());
+ }
+ }
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Primitives/CSharpType.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Primitives/CSharpType.cs
index d25aadde77..eaaee6179b 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Primitives/CSharpType.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Primitives/CSharpType.cs
@@ -146,7 +146,7 @@ internal CSharpType(
implementation.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public) && arguments.All(t => t.IsPublic),
implementation.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Struct),
baseType,
- implementation is EnumProvider enumProvider ? enumProvider.ValueType.FrameworkType : null)
+ implementation.IsEnum? implementation.EnumUnderlyingType.FrameworkType : null)
{
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs
index 90bad93cd7..c300fa2f25 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/EnumProvider.cs
@@ -4,14 +4,17 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
namespace Microsoft.Generator.CSharp.Providers
{
- public abstract class EnumProvider : TypeProvider
+ internal abstract class EnumProvider : TypeProvider
{
+ private readonly InputEnumType _inputType;
+
public static EnumProvider Create(InputEnumType input)
=> input.IsExtensible
? new ExtensibleEnumProvider(input)
@@ -19,48 +22,33 @@ public static EnumProvider Create(InputEnumType input)
protected EnumProvider(InputEnumType input)
{
+ _inputType = input;
_deprecated = input.Deprecated;
- _input = input;
-
IsExtensible = input.IsExtensible;
- ValueType = CodeModelPlugin.Instance.TypeFactory.CreateCSharpType(input.ValueType);
- IsStringValueType = ValueType.Equals(typeof(string));
- IsIntValueType = ValueType.Equals(typeof(int)) || ValueType.Equals(typeof(long));
- IsFloatValueType = ValueType.Equals(typeof(float)) || ValueType.Equals(typeof(double));
- IsNumericValueType = IsIntValueType || IsFloatValueType;
-
Description = input.Description != null ? FormattableStringHelpers.FromString(input.Description) : $"The {Name}.";
}
- public CSharpType ValueType { get; }
public bool IsExtensible { get; }
- internal bool IsIntValueType { get; }
- internal bool IsFloatValueType { get; }
- internal bool IsStringValueType { get; }
- internal bool IsNumericValueType { get; }
+ private bool? _isIntValue;
+ internal bool IsIntValueType => _isIntValue ??= EnumUnderlyingType.Equals(typeof(int)) || EnumUnderlyingType.Equals(typeof(long));
+ private bool? _isFloatValue;
+ internal bool IsFloatValueType => _isFloatValue ??= EnumUnderlyingType.Equals(typeof(float)) || EnumUnderlyingType.Equals(typeof(double));
+ private bool? _isStringValue;
+ internal bool IsStringValueType => _isStringValue ??= EnumUnderlyingType.Equals(typeof(string));
+ internal bool IsNumericValueType => IsIntValueType || IsFloatValueType;
protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Models", $"{Name}.cs");
- protected override string BuildName() => _input.Name.ToCleanName();
+ protected override string BuildName() => _inputType.Name.ToCleanName();
protected override FormattableString Description { get; }
- private IReadOnlyList? _members;
- private readonly InputEnumType _input;
- public IReadOnlyList Members => _members ??= BuildMembers();
-
- protected abstract IReadOnlyList BuildMembers();
-
- public abstract ValueExpression ToSerial(ValueExpression enumExpression);
-
- public abstract ValueExpression ToEnum(ValueExpression valueExpression);
-
- protected override string GetNamespace() => CodeModelPlugin.Instance.Configuration.ModelNamespace;
-
- protected override bool GetIsEnum() => true;
-
protected override TypeProvider[] BuildSerializationProviders()
{
- return [.. CodeModelPlugin.Instance.TypeFactory.CreateSerializations(_input)];
+ return CodeModelPlugin.Instance.TypeFactory.CreateSerializations(_inputType).ToArray();
}
+ protected override string GetNamespace() => CodeModelPlugin.Instance.Configuration.ModelNamespace;
+
+ protected override bool GetIsEnum() => true;
+ protected override CSharpType BuildEnumUnderlyingType() => CodeModelPlugin.Instance.TypeFactory.CreateCSharpType(_inputType.ValueType);
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs
index 1581cb9ab0..e70a102811 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ExtensibleEnumProvider.cs
@@ -19,11 +19,11 @@ internal sealed class ExtensibleEnumProvider : EnumProvider
{
private readonly IReadOnlyList _allowedValues;
private readonly TypeSignatureModifiers _modifiers;
-
+ private readonly InputEnumType _inputType;
internal ExtensibleEnumProvider(InputEnumType input): base(input)
{
+ _inputType = input;
_allowedValues = input.Values;
-
// extensible enums are implemented as readonly structs
_modifiers = TypeSignatureModifiers.Partial | TypeSignatureModifiers.ReadOnly | TypeSignatureModifiers.Struct;
if (input.Accessibility == "internal")
@@ -31,14 +31,14 @@ internal ExtensibleEnumProvider(InputEnumType input): base(input)
_modifiers |= TypeSignatureModifiers.Internal;
}
- _valueField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, ValueType, "_value");
+ _valueField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, EnumUnderlyingType, "_value");
}
private readonly FieldProvider _valueField;
protected override TypeSignatureModifiers GetDeclarationModifiers() => _modifiers;
- protected override IReadOnlyList BuildMembers()
+ protected override IReadOnlyList BuildEnumValues()
{
var values = new EnumTypeMember[_allowedValues.Count];
@@ -54,7 +54,7 @@ protected override IReadOnlyList BuildMembers()
var initializationValue = Literal(inputValue.Value);
var field = new FieldProvider(
modifiers,
- ValueType,
+ EnumUnderlyingType,
name,
FormattableStringHelpers.FromString(inputValue.Description),
initializationValue);
@@ -69,14 +69,14 @@ protected override CSharpType[] BuildImplements()
=> [new CSharpType(typeof(IEquatable<>), Type)]; // extensible enums implement IEquatable
protected override FieldProvider[] BuildFields()
- => [_valueField, .. Members.Select(v => v.Field)];
+ => [_valueField, .. EnumValues.Select(v => v.Field)];
protected override PropertyProvider[] BuildProperties()
{
- var properties = new PropertyProvider[Members.Count];
+ var properties = new PropertyProvider[EnumValues.Count];
var index = 0;
- foreach (var enumValue in Members)
+ foreach (var enumValue in EnumValues)
{
var name = enumValue.Name;
var value = enumValue.Value;
@@ -94,9 +94,9 @@ protected override PropertyProvider[] BuildProperties()
protected override ConstructorProvider[] BuildConstructors()
{
- var valueParameter = new ParameterProvider("value", $"The value.", ValueType)
+ var valueParameter = new ParameterProvider("value", $"The value.", EnumUnderlyingType)
{
- Validation = ValueType.IsValueType ? ParameterValidationType.None : ParameterValidationType.AssertNotNull
+ Validation = EnumUnderlyingType.IsValueType ? ParameterValidationType.None : ParameterValidationType.AssertNotNull
};
var signature = new ConstructorSignature(
Type: Type,
@@ -141,7 +141,7 @@ protected override MethodProvider[] BuildMethods()
methods.Add(new(inequalitySignature, Not(left.InvokeEquals(right)), this));
- var valueParameter = new ParameterProvider("value", $"The value.", ValueType);
+ var valueParameter = new ParameterProvider("value", $"The value.", EnumUnderlyingType);
var castSignature = new MethodSignature(
Name: string.Empty,
Description: $"Converts a string to a {Type:C}",
@@ -185,11 +185,11 @@ protected override MethodProvider[] BuildMethods()
// public bool Equals(EnumType other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase);
// or
// public bool Equals(EnumType other) => int/float.Equals(_value, other._value);
- var valueField = new VariableExpression(ValueType.WithNullable(!ValueType.IsValueType), _valueField.Declaration);
+ var valueField = new VariableExpression(EnumUnderlyingType.WithNullable(!EnumUnderlyingType.IsValueType), _valueField.Declaration);
var otherValue = ((ValueExpression)otherParameter).Property(_valueField.Name);
var equalsExpressionBody = IsStringValueType
- ? Static(ValueType).Invoke(nameof(object.Equals), [valueField, otherValue, FrameworkEnumValue(StringComparison.InvariantCultureIgnoreCase)])
- : Static(ValueType).Invoke(nameof(object.Equals), [valueField, otherValue]);
+ ? Static(EnumUnderlyingType).Invoke(nameof(object.Equals), [valueField, otherValue, FrameworkEnumValue(StringComparison.InvariantCultureIgnoreCase)])
+ : Static(EnumUnderlyingType).Invoke(nameof(object.Equals), [valueField, otherValue]);
methods.Add(new(equalsSignature, equalsExpressionBody, this));
var getHashCodeSignature = new MethodSignature(
@@ -231,35 +231,14 @@ protected override MethodProvider[] BuildMethods()
: valueField.Invoke(nameof(object.ToString), new MemberExpression(typeof(CultureInfo), nameof(CultureInfo.InvariantCulture)));
methods.Add(new(toStringSignature, toStringExpressionBody, this, XmlDocProvider.InheritDocs));
- // for string-based extensible enums, we are using `ToString` as its serialization
- // for non-string-based extensible enums, we need a method to serialize them
- if (!IsStringValueType)
- {
- var toSerialSignature = new MethodSignature(
- Name: $"ToSerial{ValueType.Name}",
- Modifiers: MethodSignatureModifiers.Internal,
- ReturnType: ValueType,
- Parameters: Array.Empty(),
- Description: null,
- ReturnDescription: null);
-
- // writes the method:
- // internal float ToSerialSingle() => _value; // when ValueType is float
- // internal int ToSerialInt32() => _value; // when ValueType is int
- // etc
- methods.Add(new(toSerialSignature, valueField, this));
- }
-
return methods.ToArray();
}
-
- public override ValueExpression ToSerial(ValueExpression enumExpression)
+ protected override TypeProvider[] BuildSerializationProviders()
{
- var serialMethodName = IsStringValueType ? nameof(object.ToString) : $"ToSerial{ValueType.Name}";
- return enumExpression.Invoke(serialMethodName);
+ return CodeModelPlugin.Instance.TypeFactory.CreateSerializations(_inputType).ToArray();
}
+ protected override bool GetIsEnum() => true;
- public override ValueExpression ToEnum(ValueExpression valueExpression)
- => New.Instance(Type, valueExpression);
+ protected override CSharpType BuildEnumUnderlyingType() => CodeModelPlugin.Instance.TypeFactory.CreateCSharpType(_inputType.ValueType);
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs
index c56b92fa05..f2e56850da 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/FixedEnumProvider.cs
@@ -15,11 +15,12 @@ internal sealed class FixedEnumProvider : EnumProvider
{
private readonly IReadOnlyList _allowedValues;
private readonly TypeSignatureModifiers _modifiers;
+ private readonly InputEnumType _inputType;
internal FixedEnumProvider(InputEnumType input) : base(input)
{
+ _inputType = input;
_allowedValues = input.Values;
-
// fixed enums are implemented by enum in C#
_modifiers = TypeSignatureModifiers.Enum;
if (input.Accessibility == "internal")
@@ -28,10 +29,15 @@ internal FixedEnumProvider(InputEnumType input) : base(input)
}
}
+ protected override TypeProvider[] BuildSerializationProviders()
+ {
+ return CodeModelPlugin.Instance.TypeFactory.CreateSerializations(_inputType).ToArray();
+ }
+
protected override TypeSignatureModifiers GetDeclarationModifiers() => _modifiers;
// we have to build the values first, because the corresponding fieldDeclaration of the values might need all of the existing values to avoid name conflicts
- protected override IReadOnlyList BuildMembers()
+ protected override IReadOnlyList BuildEnumValues()
{
var values = new EnumTypeMember[_allowedValues.Count];
for (int i = 0; i < _allowedValues.Count; i++)
@@ -44,7 +50,7 @@ protected override IReadOnlyList BuildMembers()
var initializationValue = IsIntValueType ? Literal(inputValue.Value) : null;
var field = new FieldProvider(
modifiers,
- ValueType,
+ EnumUnderlyingType,
name,
inputValue.Description is null ? $"{name}" : FormattableStringHelpers.FromString(inputValue.Description),
initializationValue);
@@ -55,22 +61,9 @@ protected override IReadOnlyList BuildMembers()
}
protected override FieldProvider[] BuildFields()
- => Members.Select(v => v.Field).ToArray();
-
- public override ValueExpression ToSerial(ValueExpression enumExpression)
- {
- if (IsIntValueType)
- {
- // when the fixed enum is implemented as int, we cast to the value
- return enumExpression.CastTo(ValueType);
- }
-
- // otherwise we call the corresponding extension method to convert the value
- CSharpType? serializationType = SerializationProviders.FirstOrDefault()?.Type;
- return enumExpression.Invoke($"ToSerial{ValueType.Name}");
- }
+ => EnumValues.Select(v => v.Field).ToArray();
- public override ValueExpression ToEnum(ValueExpression valueExpression)
- => valueExpression.Invoke($"To{Type.Name}");
+ protected override bool GetIsEnum() => true;
+ protected override CSharpType BuildEnumUnderlyingType() => CodeModelPlugin.Instance.TypeFactory.CreateCSharpType(_inputType.ValueType);
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs
index 601954696f..d5f4eb337f 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/TypeProvider.cs
@@ -52,6 +52,7 @@ public string? Deprecated
GetBaseType());
protected virtual bool GetIsEnum() => false;
+ public bool IsEnum => GetIsEnum();
protected virtual string GetNamespace() => CodeModelPlugin.Instance.Configuration.RootNamespace;
@@ -142,6 +143,12 @@ private TypeSignatureModifiers GetDeclarationModifiersInternal()
protected virtual TypeProvider[] BuildSerializationProviders() => Array.Empty();
+ protected virtual CSharpType BuildEnumUnderlyingType() => throw new InvalidOperationException("Not an EnumProvider type");
+
+ private CSharpType? _enumUnderlyingType;
+
+ public CSharpType EnumUnderlyingType => _enumUnderlyingType ??= BuildEnumUnderlyingType(); // Each member in the EnumProvider has to have this type
+
protected virtual XmlDocProvider BuildXmlDocs()
{
var docs = new XmlDocProvider();
@@ -190,5 +197,10 @@ public void Update(
XmlDocs = xmlDocs;
}
}
+ public IReadOnlyList EnumValues => _enumValues ??= BuildEnumValues();
+
+ protected virtual IReadOnlyList BuildEnumValues() => throw new InvalidOperationException("Not an EnumProvider type");
+
+ private IReadOnlyList? _enumValues;
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.New.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.New.cs
index bcf17264df..ba772a9b11 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.New.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Snippets/Snippet.New.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
@@ -16,8 +17,11 @@ public static partial class Snippet
{
public static class New
{
- public static ValueExpression ArgumentOutOfRangeException(EnumProvider enumType, ParameterProvider valueParameter)
- => Instance(typeof(ArgumentOutOfRangeException), Nameof(valueParameter), valueParameter, Literal($"Unknown {enumType.Name} value."));
+ public static ValueExpression ArgumentOutOfRangeException(TypeProvider provider, ParameterProvider valueParameter)
+ {
+ Debug.Assert(provider.IsEnum);
+ return Instance(typeof(ArgumentOutOfRangeException), Nameof(valueParameter), valueParameter, Literal($"Unknown {provider.Name} value."));
+ }
public static ValueExpression ArgumentOutOfRangeException(ValueExpression valueParameter, string message, bool wrapInNameOf = true)
=> Instance(typeof(ArgumentOutOfRangeException), wrapInNameOf ? Nameof(valueParameter) : valueParameter, Literal(message));
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypeFactory.cs
index e9b876723f..d26cef38c5 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypeFactory.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/TypeFactory.cs
@@ -234,15 +234,6 @@ public IReadOnlyList CreateSerializations(InputType inputType)
protected virtual IReadOnlyList CreateSerializationsCore(InputType inputType)
{
- if (inputType is InputEnumType enumType)
- {
- var provider = CreateEnum(enumType);
- if (provider is EnumProvider { IsExtensible: false } enumProvider)
- {
- return [new FixedEnumSerializationProvider(enumProvider)];
- }
- }
-
return [];
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumProviderTests.cs
index d0c906d80d..e0b1fee4d5 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumProviderTests.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/Providers/EnumProviderTests.cs
@@ -35,26 +35,6 @@ public void BuildEnumType_ValidateIntBasedFixedEnum()
var value2 = fields[1].InitializationValue as LiteralExpression;
Assert.IsNotNull(value2);
Assert.AreEqual(2, value2?.Literal);
-
- // int based fixed enum does not have serialization method therefore we only have one method
- var serialization = enumType.SerializationProviders.FirstOrDefault();
- Assert.IsNotNull(serialization);
- Assert.AreEqual(1, serialization?.Methods.Count);
-
- // validate the expression is working fine
- using var writer = new CodeWriter();
- var enumVar = new VariableExpression(enumType.Type, new TestCodeWriterDeclaration("e"));
- enumType.ToSerial(enumVar).Write(writer);
- writer.WriteLine();
- enumType.ToEnum(Snippet.Literal(1)).Write(writer);
-
- var result = writer.ToString(false);
- var builder = new StringBuilder();
- builder.Append($"((int)e)").Append(NewLine)
- .Append($"1.ToMockInputEnum()");
- var expected = builder.ToString();
-
- Assert.AreEqual(expected, result);
}
// Validates the float based fixed enum
@@ -73,26 +53,6 @@ public void BuildEnumType_ValidateFloatBasedFixedEnum()
// non-int based enum does not initialization values.
Assert.IsNull(fields[0].InitializationValue);
Assert.IsNull(fields[1].InitializationValue);
-
- // int float fixed enum has serialization method and deserialization method therefore we only have two methods
- var serialization = enumType.SerializationProviders.FirstOrDefault();
- Assert.IsNotNull(serialization);
- Assert.AreEqual(2, serialization?.Methods.Count);
-
- // validate the expression is working fine
- using var writer = new CodeWriter();
- var enumVar = new VariableExpression(enumType.Type, new TestCodeWriterDeclaration("e"));
- enumType.ToSerial(enumVar).Write(writer);
- writer.WriteLine();
- enumType.ToEnum(Snippet.Literal(1f)).Write(writer);
-
- var result = writer.ToString(false);
- var builder = new StringBuilder();
- builder.Append($"e.ToSerialSingle()").Append(NewLine)
- .Append($"1F.ToMockInputEnum()");
- var expected = builder.ToString();
-
- Assert.AreEqual(expected, result);
}
// Validates the string based fixed enum
@@ -111,26 +71,6 @@ public void BuildEnumType_ValidateStringBasedFixedEnum()
// non-int based enum does not initialization values.
Assert.IsNull(fields[0].InitializationValue);
Assert.IsNull(fields[1].InitializationValue);
-
- // int float fixed enum has serialization method and deserialization method therefore we only have two methods
- var serialization = enumType.SerializationProviders.FirstOrDefault();
- Assert.IsNotNull(serialization);
- Assert.AreEqual(2, serialization?.Methods.Count);
-
- // validate the expression is working fine
- using var writer = new CodeWriter();
- var enumVar = new VariableExpression(enumType.Type, new TestCodeWriterDeclaration("e"));
- enumType.ToSerial(enumVar).Write(writer);
- writer.WriteLine();
- enumType.ToEnum(Snippet.Literal("1")).Write(writer);
-
- var result = writer.ToString(false);
- var builder = new StringBuilder();
- builder.Append($"e.ToSerialString()").Append(NewLine)
- .Append($"\"1\".ToMockInputEnum()");
- var expected = builder.ToString();
-
- Assert.AreEqual(expected, result);
}
// Validates the int based extensible enum
@@ -169,25 +109,6 @@ public void BuildEnumType_ValidateIntBasedExtensibleEnum()
Assert.IsInstanceOf(properties[1].Body);
var propertyValue2 = (properties[1].Body as AutoPropertyBody)?.InitializationExpression;
Assert.IsNotNull(propertyValue2);
-
- // extensible enums do not have serialization
- var serialization = enumType.SerializationProviders.FirstOrDefault();
- Assert.IsNull(serialization);
-
- // validate the expression is working fine
- using var writer = new CodeWriter();
- var enumVar = new VariableExpression(enumType.Type, new TestCodeWriterDeclaration("e"));
- enumType.ToSerial(enumVar).Write(writer);
- writer.WriteLine();
- enumType.ToEnum(Snippet.Literal(1)).Write(writer);
-
- var result = writer.ToString(false);
- var builder = new StringBuilder();
- builder.Append($"e.ToSerialInt32()").Append(NewLine)
- .Append($"new global::Sample.Models.MockInputEnum(1)");
- var expected = builder.ToString();
-
- Assert.AreEqual(expected, result);
}
// Validates the float based extensible enum
@@ -226,25 +147,6 @@ public void BuildEnumType_ValidateFloatBasedExtensibleEnum()
Assert.IsInstanceOf(properties[1].Body);
var propertyValue2 = (properties[1].Body as AutoPropertyBody)?.InitializationExpression;
Assert.IsNotNull(propertyValue2);
-
- // extensible enums do not have serialization
- var serialization = enumType.SerializationProviders.FirstOrDefault();
- Assert.IsNull(serialization);
-
- // validate the expression is working fine
- using var writer = new CodeWriter();
- var enumVar = new VariableExpression(enumType.Type, new TestCodeWriterDeclaration("e"));
- enumType.ToSerial(enumVar).Write(writer);
- writer.WriteLine();
- enumType.ToEnum(Snippet.Literal(1f)).Write(writer);
-
- var result = writer.ToString(false);
- var builder = new StringBuilder();
- builder.Append($"e.ToSerialSingle()").Append(NewLine)
- .Append($"new global::Sample.Models.MockInputEnum(1F)");
- var expected = builder.ToString();
-
- Assert.AreEqual(expected, result);
}
// Validates the string based extensible enum
@@ -283,25 +185,6 @@ public void BuildEnumType_ValidateStringBasedExtensibleEnum()
Assert.IsInstanceOf(properties[1].Body);
var propertyValue2 = (properties[1].Body as AutoPropertyBody)?.InitializationExpression;
Assert.IsNotNull(propertyValue2);
-
- // extensible enums do not have serialization
- var serialization = enumType.SerializationProviders.FirstOrDefault();
- Assert.IsNull(serialization);
-
- // validate the expression is working fine
- using var writer = new CodeWriter();
- var enumVar = new VariableExpression(enumType.Type, new TestCodeWriterDeclaration("e"));
- enumType.ToSerial(enumVar).Write(writer);
- writer.WriteLine();
- enumType.ToEnum(Snippet.Literal("1")).Write(writer);
-
- var result = writer.ToString(false);
- var builder = new StringBuilder();
- builder.Append($"e.ToString()").Append(NewLine)
- .Append($"new global::Sample.Models.MockInputEnum(\"1\")");
- var expected = builder.ToString();
-
- Assert.AreEqual(expected, result);
}
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.Serialization.cs
new file mode 100644
index 0000000000..febd945df2
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct AnonymousBodyRequestOptionalLiteralFloat
+ {
+ internal float ToSerialSingle() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.cs
index 72158746d5..11c5b3d662 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralFloat.cs
@@ -51,7 +51,5 @@ public AnonymousBodyRequestOptionalLiteralFloat(float value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal float ToSerialSingle() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.Serialization.cs
new file mode 100644
index 0000000000..7c4a796aff
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct AnonymousBodyRequestOptionalLiteralInt
+ {
+ internal int ToSerialInt32() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.cs
index 0eb1341eb5..776242170f 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestOptionalLiteralInt.cs
@@ -51,7 +51,5 @@ public AnonymousBodyRequestOptionalLiteralInt(int value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal int ToSerialInt32() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.Serialization.cs
new file mode 100644
index 0000000000..66d470aef9
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct AnonymousBodyRequestRequiredLiteralFloat
+ {
+ internal float ToSerialSingle() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.cs
index cbdad0a478..bcbcfee230 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralFloat.cs
@@ -51,7 +51,5 @@ public AnonymousBodyRequestRequiredLiteralFloat(float value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal float ToSerialSingle() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.Serialization.cs
new file mode 100644
index 0000000000..9d0e39342d
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct AnonymousBodyRequestRequiredLiteralInt
+ {
+ internal int ToSerialInt32() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.cs
index ddc2cbd76c..bdf57f3e45 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/AnonymousBodyRequestRequiredLiteralInt.cs
@@ -51,7 +51,5 @@ public AnonymousBodyRequestRequiredLiteralInt(int value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal int ToSerialInt32() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.Serialization.cs
new file mode 100644
index 0000000000..956cb7a2dc
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct FloatExtensibleEnum
+ {
+ internal float ToSerialSingle() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs
index a2834b06ed..fca2c0da28 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnum.cs
@@ -58,7 +58,5 @@ public FloatExtensibleEnum(float value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal float ToSerialSingle() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.Serialization.cs
new file mode 100644
index 0000000000..88300214e2
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct FloatExtensibleEnumWithIntValue
+ {
+ internal float ToSerialSingle() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs
index f84dcb4ccb..4269f9144c 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatExtensibleEnumWithIntValue.cs
@@ -58,7 +58,5 @@ public FloatExtensibleEnumWithIntValue(float value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal float ToSerialSingle() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnum.Serialization.cs
similarity index 100%
rename from packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumExtensions.cs
rename to packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnum.Serialization.cs
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValueExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValue.Serialization.cs
similarity index 100%
rename from packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValueExtensions.cs
rename to packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/FloatFixedEnumWithIntValue.Serialization.cs
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.Serialization.cs
new file mode 100644
index 0000000000..5f92623cca
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct IntExtensibleEnum
+ {
+ internal int ToSerialInt32() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs
index 33b8096b0a..172c9fc2bd 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntExtensibleEnum.cs
@@ -58,7 +58,5 @@ public IntExtensibleEnum(int value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal int ToSerialInt32() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnumExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnum.Serialization.cs
similarity index 100%
rename from packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnumExtensions.cs
rename to packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/IntFixedEnum.Serialization.cs
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnumExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnum.Serialization.cs
similarity index 100%
rename from packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnumExtensions.cs
rename to packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/StringFixedEnum.Serialization.cs
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.Serialization.cs
new file mode 100644
index 0000000000..d9239e6290
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct ThingOptionalLiteralFloat
+ {
+ internal float ToSerialSingle() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs
index 07d545a9fa..ff2a824901 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralFloat.cs
@@ -51,7 +51,5 @@ public ThingOptionalLiteralFloat(float value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal float ToSerialSingle() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.Serialization.cs
new file mode 100644
index 0000000000..e498f97ed1
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct ThingOptionalLiteralInt
+ {
+ internal int ToSerialInt32() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs
index 0bb5abbb7c..705a41a01d 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingOptionalLiteralInt.cs
@@ -51,7 +51,5 @@ public ThingOptionalLiteralInt(int value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal int ToSerialInt32() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.Serialization.cs
new file mode 100644
index 0000000000..c2b1deae37
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct ThingRequiredLiteralFloat
+ {
+ internal float ToSerialSingle() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs
index 8b0713c99e..bbd25a140b 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralFloat.cs
@@ -51,7 +51,5 @@ public ThingRequiredLiteralFloat(float value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal float ToSerialSingle() => _value;
}
}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.Serialization.cs
new file mode 100644
index 0000000000..d0e1af2a01
--- /dev/null
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.Serialization.cs
@@ -0,0 +1,12 @@
+//
+
+#nullable disable
+
+namespace UnbrandedTypeSpec.Models
+{
+ ///
+ public readonly partial struct ThingRequiredLiteralInt
+ {
+ internal int ToSerialInt32() => _value;
+ }
+}
diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs
index 2a067b2625..ade27db4a9 100644
--- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs
+++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/Models/ThingRequiredLiteralInt.cs
@@ -51,7 +51,5 @@ public ThingRequiredLiteralInt(int value)
///
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
-
- internal int ToSerialInt32() => _value;
}
}