<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Wed Feb 07 21:35:53 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[CSHARP-125] Enum deserialization appears to rely on the underlying type of the CURRENT C# Enum to deserialize Enums - backward compatibility issue?</title>
                <link>https://jira.mongodb.org/browse/CSHARP-125</link>
                <project id="10041" key="CSHARP">C# Driver</project>
                    <description>

&lt;p&gt;Reading through the code for EnumSerializer.Deserialize there is a switch statement that uses the underlying type of the C# Enum being deserialized to determine what to read from the database.  Isn&apos;t this backwards?  Shouldn&apos;t it read the value from the database according to the stored Bson type (whatever it is: Int32, Int64, double, ...) and THEN see if it can fit that value into the CURRENT underlying type of the Enum?&lt;/p&gt;

&lt;p&gt;Suppose I have a flags  Enum today that fits in an Int32.  That will get saved to the database as a BSon int32.  Now I add one more flag that pushes it to need an Int64.  Next time I save a value it gets saved as a Bson Int64, that&apos;s fine and I can read it back out.  BUT now, none of my existing documents (that were serialized when my Enum used to fit in an Int32) will deserialize because this code will look at the current underlying type (Int64) and then try to read an Int64 when in fact the legacy records have Int32&apos;s in them.&lt;/p&gt;

&lt;p&gt;The alternative direction is also possible but less likely (perhaps you have a flags enum with a high order bit that has never been used - you remove it from the enum and now it fits in a smaller underlying type).&lt;/p&gt;

&lt;p&gt;Suggestion:&lt;/p&gt;

&lt;p&gt;Read whatever numeric type is in the database, then check that it fits in the CURRENT underlying type. &lt;/p&gt;

&lt;p&gt;Separately, allowing this code to also read a BSon Double and returning an Enum from that will solve a different issue which is that Enums round-tripped through Map Reduce come back as doubles and then can&apos;t be deserialized back into an Enum.&lt;/p&gt;


&lt;p&gt;Excuse the ugly repetition ... but for the purposes of illustrating what I mean ... something like this seems to work and will solve both the backward compatibility issue and the map-reduce round trip problem.&lt;/p&gt;

&lt;p&gt;        public override object Deserialize(&lt;br/&gt;
            BsonReader bsonReader,&lt;br/&gt;
            Type nominalType&lt;br/&gt;
        ) {&lt;br/&gt;
            VerifyNominalType(nominalType);&lt;br/&gt;
            var bsonType = bsonReader.CurrentBsonType;&lt;br/&gt;
            if (bsonType == BsonType.String) &lt;/p&gt;
{
                var value = bsonReader.ReadString();
                return Enum.Parse(nominalType, value);
            }
&lt;p&gt;            else if (bsonType == BsonType.Double)&lt;br/&gt;
            {&lt;br/&gt;
                int value = (int)bsonReader.ReadDouble();&lt;br/&gt;
                switch (Type.GetTypeCode(Enum.GetUnderlyingType(nominalType))) &lt;/p&gt;
{
                    case TypeCode.Byte: return (byte) value;
                    case TypeCode.Int16: return (short) value;
                    case TypeCode.Int32: return (int)value;
                    case TypeCode.Int64: return (long)value;
                    case TypeCode.SByte: return (sbyte) value;
                    case TypeCode.UInt16: return (ushort) value;
                    case TypeCode.UInt32: return (uint) value;
                    case TypeCode.UInt64: return (ulong) value;
                    default: throw new BsonSerializationException(&quot;Unrecognized underlying type for enum&quot;);
            }
&lt;p&gt;            }&lt;br/&gt;
            else if (bsonType == BsonType.Int32)&lt;br/&gt;
            {&lt;br/&gt;
                int value = bsonReader.ReadInt32();&lt;br/&gt;
                switch (Type.GetTypeCode(Enum.GetUnderlyingType(nominalType)))&lt;/p&gt;
                {
                    case TypeCode.Byte: return (byte)value;
                    case TypeCode.Int16: return (short)value;
                    case TypeCode.Int32: return (int)value;
                    case TypeCode.Int64: return (long)value;
                    case TypeCode.SByte: return (sbyte)value;
                    case TypeCode.UInt16: return (ushort)value;
                    case TypeCode.UInt32: return (uint)value;
                    case TypeCode.UInt64: return (ulong)value;
                    default: throw new BsonSerializationException(&quot;Unrecognized underlying type for enum&quot;);
                }
&lt;p&gt;            }&lt;br/&gt;
            else if (bsonType == BsonType.Int64)&lt;br/&gt;
            {&lt;br/&gt;
                long value = bsonReader.ReadInt64();&lt;br/&gt;
                switch (Type.GetTypeCode(Enum.GetUnderlyingType(nominalType)))&lt;/p&gt;
                {
                    case TypeCode.Byte: return (byte)value;
                    case TypeCode.Int16: return (short)value;
                    case TypeCode.Int32: return (int)value;
                    case TypeCode.Int64: return (long)value;
                    case TypeCode.SByte: return (sbyte)value;
                    case TypeCode.UInt16: return (ushort)value;
                    case TypeCode.UInt32: return (uint)value;
                    case TypeCode.UInt64: return (ulong)value;
                    default: throw new BsonSerializationException(&quot;Unrecognized underlying type for enum&quot;);
                }
&lt;p&gt;            }&lt;br/&gt;
            else&lt;br/&gt;
                throw new BsonSerializationException(&quot;Enums can&apos;t be read from &quot; + bsonType);&lt;br/&gt;
        }&lt;/p&gt;</description>
                <environment></environment>
        <key id="13861">CSHARP-125</key>
            <summary>Enum deserialization appears to rely on the underlying type of the CURRENT C# Enum to deserialize Enums - backward compatibility issue?</summary>
                <type id="1" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14703&amp;avatarType=issuetype">Bug</type>
                                            <priority id="3" iconUrl="https://jira.mongodb.org/images/icons/priorities/major.svg">Major - P3</priority>
                        <status id="6" iconUrl="https://jira.mongodb.org/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="success"/>
                                    <resolution id="9">Done</resolution>
                                        <assignee username="robert@mongodb.com">Robert Stam</assignee>
                                    <reporter username="ianmercer">Ian Mercer</reporter>
                        <labels>
                    </labels>
                <created>Sat, 4 Dec 2010 06:27:34 +0000</created>
                <updated>Thu, 2 Apr 2015 18:28:11 +0000</updated>
                            <resolved>Sat, 4 Dec 2010 21:14:15 +0000</resolved>
                                    <version>0.7</version>
                                    <fixVersion>0.9</fixVersion>
                                                        <votes>0</votes>
                                    <watches>0</watches>
                                                                                                                <comments>
                            <comment id="21055" author="rstam" created="Sat, 4 Dec 2010 21:14:15 +0000"  >&lt;p&gt;Changed EnumSerializer to add Int64 representation and to be flexible about converting between numeric types when deserializing. Added more unit tests for enums of different underlying integeral types.&lt;/p&gt;</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hrh9jj:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>14345</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            </customfields>
    </item>
</channel>
</rss>