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

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

I\'d like to be able to say


<
5条回答
  •  时光说笑
    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:

        /// 
        /// Helper method to try to convert a value to an enumeration value.
        /// 
        /// If  is not convertable to , an exception will be thrown
        /// as documented by Convert.ChangeType.
        /// 
        /// The value to convert to the enumeration type.
        /// The enumeration type value.
        /// true if value was successfully converted; false otherwise.
        /// Thrown if  is not an enum type. (Because we can't specify a generic constraint that T is an Enum.)
        public static bool TryAsEnum( 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.

提交回复
热议问题