Почему и как (внутренне) выполняет Enum.IsDefined поиск имени и значения?

Допустим, мы определили Planets enum:

public enum Planets
{
    Sun = 0,
    Mercury=5,          
    Venus,              
    Earth,          
    Jupiter,        
    Uranus,         
    Neptune   
}

Я использовал метод Enum.IsDefined для определения, существует ли строка в перечислении или нет.

Enum.IsDefined(typeof(Planets), "Mercury"); // result is true

Но затем я попробовал это, и он также вернул true:

Enum.IsDefined(typeof(Planets), 5); // result is true again

Как это получается? Этот метод не имеет перегрузки. Он имеет только одну подпись:

Enum.IsDefined(Type enumType, object value);

Зачем и как Enum.IsDefined искать как имя, так и значение? И мне действительно интересно, почему они так решили? ИМО, делающий перегрузки, будет лучшим выбором, а не?

Ответ 1

Из метода Enum.IsDefined

Параметр value может быть любым из следующих:

  • Любой член типа enumType.
  • Переменная, значение которой является элементом перечисления типа enumType.
  • Строковое представление имени элемента перечисления. Символы в строке должны иметь тот же случай, что и перечисление имя участника.
  • Значение базового типа enumType.

Я считаю, что причина, по которой он не имеет перегрузки, принимает object как второй параметр. Поскольку этот метод принимает object как второй параметр, а object является базовым классом для всех типов .NET - вы можете передать string или int или etc..

Вот как этот метод реализован;

public static bool IsDefined(Type enumType, Object value)
{
     if (enumType == null)
         throw new ArgumentNullException("enumType");                    
     return enumType.IsEnumDefined(value);
}

И похоже, что этот виртуальный Type.IsEnumDefined метод обрабатывает все эти случаи в нем реализация;

    public virtual bool IsEnumDefined(object value)
    {
        if (value == null)
            throw new ArgumentNullException("value");

        if (!IsEnum)
            throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
        Contract.EndContractBlock();

        // Check if both of them are of the same type
        Type valueType = value.GetType();

        // If the value is an Enum then we need to extract the underlying value from it
        if (valueType.IsEnum)
        {
            if (!valueType.IsEquivalentTo(this))
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType", valueType.ToString(), this.ToString()));

            valueType = valueType.GetEnumUnderlyingType();
        }

        // If a string is passed in
        if (valueType == typeof(string))
        {
            string[] names = GetEnumNames();
            if (Array.IndexOf(names, value) >= 0)
                return true;
            else
                return false;
        }

        // If an enum or integer value is passed in
        if (Type.IsIntegerType(valueType))
        {
            Type underlyingType = GetEnumUnderlyingType();
            // We cannot compare the types directly because valueType is always a runtime type but underlyingType might not be.
            if (underlyingType.GetTypeCodeImpl() != valueType.GetTypeCodeImpl())
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), underlyingType.ToString()));

            Array values = GetEnumRawConstantValues();
            return (BinarySearch(values, value) >= 0);
        }
    }

Ответ 2

В документации для Enum.IsDefined указано, что это значение

Тип: System.Object

Значение или имя константы в enumType.

Вы дали Меркурию значение 5, поэтому оно может видеть это