sgjsakura / AspNetCore

ASP.NET Core Extension Library
Apache License 2.0
162 stars 26 forks source link

Enums that don't inherit from int throw errors when attempting to bind #48

Open AzaleaHarper opened 2 years ago

AzaleaHarper commented 2 years ago

In our project we use enums that are inheriting from byte, but the FlagsEnumModelBinder and FlagsEnumModelBinderProvider only handle the case where the enum is of type int.

I've managed to get it to work as intended by checking the underlying enum type and then returning a model binder that matches that type.

FlagsEnumModelBinderProvider

public IModelBinder GetBinder([NotNull] ModelBinderProviderContext context)
        {
            if (context == null)
                throw new ArgumentNullException(nameof(context));

            if (IsNotFlagsEnum(context))
            {
                return null;
            }

            var enumType
                = Enum.GetUnderlyingType(context.Metadata.UnderlyingOrModelType);

            if (enumType == typeof(int))
            {
                return new FlagsEnumIntModelBinder();
            }
            if (enumType == typeof(byte))
            {
                return new FlagsEnumByteModelBinder();
            }
            if (enumType == typeof(short))
            {
                return new FlagsEnumShortModelBinder();
            }
            if (enumType == typeof(long))
            {
                return new FlagsEnumLongModelBinder();
            }

            throw new InvalidOperationException(
                $"enums inheriting of type '{enumType.FullName}' are not supporeted.");
        }

And then in each ModelBinder on the aggregate I change the cast to the expected type. byte var result = actualValues.Aggregate(0, (current, value) => (byte)(current | (byte)value)); short var result = actualValues.Aggregate(0, (current, value) => (short)((short)current | (short)value)); long var result = actualValues.Aggregate((long)0, (current, value) => (current | (long)value));

AdamWillden commented 2 years ago

@sgjsakura we found the simpler fix which is to change this line

from: var result = actualValues.Aggregate(0, (current, value) => current | (int)value); to: var result = actualValues.Aggregate(0UL, (current, value) => current | Convert.ToUInt64(value));