protobuf-net/protobuf-net

Occasionally inconsistent order of Serializer.GetProto<FooEnum>() in .NET 6 and earlier versions

Open

#1,102 opened on Oct 16, 2023

View on GitHub
 (11 comments) (0 reactions) (1 assignee)C# (1,036 forks)batch import
bughelp wantedup-for-grabs

Repository metrics

Stars
 (4,426 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

When running Serializer.GetProto<FooEnum>() in .NET 3.1 and .NET 6.0, the order of the returned string is occasionally inconsistent except for the leading 0.

Given a FooEnum

using ProtoBuf;

namespace Bar
{
    [ProtoContract]
    public enum FooEnum
    {
        [ProtoEnum]
        A,

        [ProtoEnum]
        B,

        [ProtoEnum]
        C,
    }
}

After running Serializer.GetProto<FooEnum>(), the expected protobuf is

syntax = "proto3";
package Bar;

enum FooEnum {
   A = 0;
   B = 1;
   C = 2;
}

However, it occasionally be

syntax = "proto3";
package Bar;

enum FooEnum {
   A = 0;
   C = 2;
   B = 1;
}

I tested with a FooEnum with 17 members, the inconsistent order occurred 1 out of 183, 705, 715, 1004, 705 runs. The inconsistent order might be caused by

  1. Get MemberInfo[] by System.Type.GetMembers() in MetaType.cs
  2. Write enum members sequentially in MetaType.cs

According to the definition of Type.GetMembers()

In .NET 6 and earlier versions, the GetMembers method does not return members in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which members are returned, because that order varies. However, starting with .NET 7, the ordering is deterministic based upon the metadata ordering in the assembly.

When I deliberately alter the sequence of MemberInfo[] retrieved from Type.GetMembers() in my forked branch, the disorder becomes consistently reproducible.

Contributor guide