Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EnumMember is not applied when enum value is a combination of flags. #1016

Open
filzrev opened this issue Dec 3, 2024 · 5 comments
Open

Comments

@filzrev
Copy link
Contributor

filzrev commented Dec 3, 2024

Describe the bug
When serialize enum value combinations.
value is serialized by default enum name.
And the name that is specified by EnumMember is not used.

To Reproduce

Test Code

[Flags]
public enum TestEnum
{
	[JsonStringEnumMemberName("A")]
	[EnumMember(Value = "A")]
	AAA = 1,
	[JsonStringEnumMemberName("B")]
	[EnumMember(Value = "B")]
	BBB = 2,
}

public class Tests
{
    [Fact]
    public void YamlDotNetTest()
    {
          var serializer = new SerializerBuilder().Build();

          // Arrange
          var value = TestEnum.AAA | TestEnum.BBB;

          // Act
          var result = serializer.Serialize(value);

          // Assert
          result.Should().Be("A, B\r\n"); // Failed. Expected: "A,B\r\n" but Actual: "AAA, BBB\r\n"
    }
}

Serialize result of System.Text.Json / NewtonsoftJson

When serialize same value with System.Text.Json / NewtonsoftJson enum value is serialized as expected.

// System.Text.Json use `JsonStringEnumMemberName` attribute (EnumMember attribute is not used)
[Fact]
public void SystemTextJsonTest()
{	
	var options = new JsonSerializerOptions { };
	options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
	
	// Arrange
	var value = TestEnum.AAA | TestEnum.BBB;

	// Act
	var result = System.Text.Json.JsonSerializer.Serialize(value, options);

	// Assert
	result.Should().Be("\"A, B\""); // Success
}

// NewtonsoftJson use `EnumMember` attribute.
[Fact]
public void NewtonsoftJsonTest()
{
	// Arrange
	var value = TestEnum.AAA | TestEnum.BBB;

	// Act
	var result = JsonConvert.SerializeObject(value, new Newtonsoft.Json.Converters.StringEnumConverter());

	// Assert
	result.Should().Be("\"A, B\""); // Success
}
@EdwardCooke
Copy link
Collaborator

We do support enum member but only in .net core. Full framework doesn’t have that functionality. Are you doing this in a .net core 6/7/8 app or full framework 4.x?

@filzrev
Copy link
Contributor Author

filzrev commented Dec 4, 2024

I'm using .NET 8 or later.
So there is no need for .NET Framework supports on my usecase.

By the way, is there any reasons that exclude EnumMember support for .NET Framework 4.x?

It's explicitly excluded by #ifdef preprocessors.
But these code seems it can successfully build when targeting .NET Framework 4.7 or later. (It support .NET Standard 2.0)

public override string GetEnumName(Type enumType, string name)
{
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
foreach (var enumMember in enumType.GetMembers())
{
var attribute = enumMember.GetCustomAttribute<EnumMemberAttribute>();
if (attribute?.Value == name)
{
return enumMember.Name;
}
}
#endif
return name;
}
public override string GetEnumValue(object enumValue)
{
if (enumValue == null)
{
return string.Empty;
}
var result = enumValue.ToString();
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
var type = enumValue.GetType();
var enumMembers = type.GetMember(result);
if (enumMembers.Length > 0)
{
var attribute = enumMembers[0].GetCustomAttribute<EnumMemberAttribute>();
if (attribute?.Value != null)
{
result = attribute.Value;
}
}
#endif
return result!;
}

@EdwardCooke
Copy link
Collaborator

There was a reason for it. I just don’t remember what it was when I put that feature in place.

@EdwardCooke
Copy link
Collaborator

What version of the library are you using? And can you share the code you’re using for the serializerbuilder? I can try and take a closer look in the next few days but I suspect it’s because it’s a multi value enum value. I only tested if it’s a single value, if it was AAA or BBB not AAA|BBB. If you want to take a stab at fixing that i do accept pull requests and it might get fixed quicker.

@filzrev
Copy link
Contributor Author

filzrev commented Dec 6, 2024

What version of the library are you using? And can you share the code you’re using for the serializerbuilder?

TestCode is described on above Test Code section.
And I'm using following project references.

  <ItemGroup>
    <PackageReference Include="FluentAssertions" Version="7.0.0" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="System.Text.Json" Version="9.0.0" />
    <PackageReference Include="YamlDotNet" Version="16.2.1" />
    <PackageReference Include="xunit" Version="2.9.2" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

On my actual test code.
I'm using JsonCompatible() to comparing JSON serialized Result between YamlDotNet, System.Text.Json and NewtonsoftJson. Though it's not relating to this behaviors.

Reported Issue is occurred when passing combined flags enums.
When passed simple enum value. I can successfully serialized by using EnumMember attribute value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants