Is it possible to create a generic Int-to-Enum Converter?

后端 未结 5 791
自闭症患者
自闭症患者 2020-12-19 01:43

I\'d like to be able to say


<
相关标签:
5条回答
  • 2020-12-19 02:08

    You could do a ToString() on the int value and then pass that into the static Enum.Parse or Enum.TryParse method which takes the enum type you care about and returns the appropriate value.

    This isn't a perfect solution though because it won't work with integers that represent the binary ORing of multiple enum values

    0 讨论(0)
  • 2020-12-19 02:21

    We've wanted to do this a few times in the past as well, so we built several extension methods (on int, long, etc) to help us out. The core of all of these is implemented in a single static generic TryAsEnum method:

        /// <summary>
        /// Helper method to try to convert a value to an enumeration value.
        /// 
        /// If <paramref name="value"/> is not convertable to <typeparam name="TEnum"/>, an exception will be thrown
        /// as documented by Convert.ChangeType.
        /// </summary>
        /// <param name="value">The value to convert to the enumeration type.</param>
        /// <param name="outEnum">The enumeration type value.</param>
        /// <returns>true if value was successfully converted; false otherwise.</returns>
        /// <exception cref="InvalidOperationException">Thrown if <typeparamref name="TEnum"/> is not an enum type. (Because we can't specify a generic constraint that T is an Enum.)</exception>
        public static bool TryAsEnum<TValue, TEnum>( TValue value, out TEnum outEnum ) where TEnum : struct
        {
            var enumType = typeof( TEnum );
    
            if ( !enumType.IsEnum )
            {
                throw new InvalidOperationException( string.Format( "{0} is not an enum type.", enumType.Name ) );
            }
    
            var valueAsUnderlyingType = Convert.ChangeType( value, Enum.GetUnderlyingType( enumType ) );
    
            if ( Enum.IsDefined( enumType, valueAsUnderlyingType ) )
            {
                outEnum = (TEnum) Enum.ToObject( enumType, valueAsUnderlyingType );
                return true;
            }
    
            // IsDefined returns false if the value is multiple composed flags, so detect and handle that case
    
            if( enumType.GetCustomAttributes( typeof( FlagsAttribute ), inherit: true ).Any() )
            {
                // Flags attribute set on the enum. Get the enum value.
                var enumValue = (TEnum)Enum.ToObject( enumType, valueAsUnderlyingType );
    
                // If a value outside the actual enum range is set, then ToString will result in a numeric representation (rather than a string one).
                // So if a number CANNOT be parsed from the ToString result, we know that only defined values have been set.
                decimal parseResult;
                if( !decimal.TryParse( enumValue.ToString(), out parseResult ) )
                {
                    outEnum = enumValue;
                    return true;
                }
            }
    
            outEnum = default( TEnum );
            return false;
        }
    

    This implementation handles Enums with any underlying type, as well as enums defined with the [Flags] attribute.

    0 讨论(0)
  • 2020-12-19 02:22

    You could also go the other way around and convert the enum to int for the Value using a custom Markup Extension.

    Example

    <DataTrigger Binding="{Binding Path=MyNumber}"
                 Value="{Markup:EnumToInt {x:Static Visibility.Visible}}">
    

    EnumToIntExtension

    public class EnumToIntExtension : MarkupExtension
    {
        public object EnumValue
        {
            get;
            set;
        }
        public EnumToIntExtension(object enumValue)
        {
            this.EnumValue = enumValue;
        } 
        public override object ProvideValue(IServiceProvider provider)
        {
            if (EnumValue != null && EnumValue is Enum)
            {
                return System.Convert.ToInt32(EnumValue);
            }
            return -1;
        }
    }
    
    0 讨论(0)
  • 2020-12-19 02:25

    I think I figured it out

    I just needed to set my ConverterParameter instead of the Value equal to the Enum I am looking for, and evaluate for True/False

    <DataTrigger Value="True"
                 Binding="{Binding SomeIntValue, 
                     Converter={StaticResource IsIntEqualEnumConverter},
                     ConverterParameter={x:Static local:MyEnum.SomeValue}}">
    

    Converter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (parameter == null || value == null) return false;
    
        if (parameter.GetType().IsEnum && value is int)
        {
            return (int)parameter == (int)value;
        } 
        return false;
    }
    
    0 讨论(0)
  • 2020-12-19 02:32

    It is possible to create a converter between enum values and their underlying integral types in a reusable way -- that is, you don't need to define a new converter for each enum types. There's enough information provided to Convert and ConvertBack for this.

    public sealed class BidirectionalEnumAndNumberConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return null;
    
            if (targetType.IsEnum)
            {
                // convert int to enum
                return Enum.ToObject(targetType, value);
            }
    
            if (value.GetType().IsEnum)
            {
                // convert enum to int
                return System.Convert.ChangeType(
                    value,
                    Enum.GetUnderlyingType(value.GetType()));
            }
    
            return null;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // perform the same conversion in both directions
            return Convert(value, targetType, parameter, culture);
        }
    }
    

    When invoked, this converter flips the value's type between int/enum value based purely on the value and targetType values. There are no hard-coded enum types.

    0 讨论(0)
提交回复
热议问题