Search code examples
mapperly

How can I get build time errors on string to Enum mappings?


I have enabled strict enum mappings in my .editorconfig. For my enums I'm using EnumMappingStrategy.ByName globally.

The problem is that the strictness only applies to enum-to-enum conversion, and for string-to-enum I get this code generated resulting in runtime errors:

        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.4.0.0")]
        private global::Blue.Tests.Logic.Baz MapToBaz(string source)
        {
            return source switch
            {
                nameof(global::Blue.Tests.Logic.Baz.Cux) => global::Blue.Tests.Logic.Baz.Cux,
                _ => System.Enum.Parse<global::Blue.Tests.Logic.Baz>(source, false),
            };
        }

I tried disabling the built-in converter using EnabledConversions= MappingConversionType.All & ~MappingConversionType.StringToEnum. That however results in this:

        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.4.0.0")]
        public partial global::Blue.Tests.Logic.Bar? Map(global::Blue.Tests.Logic.Foo? from)
        {
            if (from == null)
                return default;
            var target = new global::Blue.Tests.Logic.Bar();
            if (from.Status != null)
            {
                target.Status = (global::Blue.Tests.Logic.Baz)int.Parse(from.Status);
            }
            return target;
        }

One of the reasons I switched to Mapperly was to avoid reflection based libraries resulting in runtime errors. The generated code in the last example feels like a bug or an oversight.

Is there a way to get a build error when accidentally mapping from string to enum?


Solution

  • This is expected behaviour. Mapperly tries to build a conversion using all enabled conversions in order of their priority. In this case the StringToEnum conversion is disabled. If Mapperly cannot map to the enum directly, it tries to map to the underlaying type and cast that value to the enum type. This is exactly what happens here:

    • Mapperly tries to find a Mapping from string to int which is found by int.Parse
    • the resulting underlaying type is then explicitly casted to the enum type

    If you don't want this to happen you may need to disable the explicit cast conversion as well. Just reporting an error for all string to enum mappings is not supported by Mapperly (yet), see https://github.com/riok/mapperly/issues/1176.