Question

Lets say we have defined Planets enum:

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

I was using Enum.IsDefined method for finding whether string exists in enum or not.

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

But, then I tried this and it returned true also:

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

How, it comes? This method has not any overload. It has only one signature:

Enum.IsDefined(Type enumType, object value);

Why and how is Enum.IsDefined searching for both name and value? And it is really interesting to me, why did they chosed that way? IMO making overloads would be better choice, not?

Était-ce utile?

La solution

From Enum.IsDefined method

The value parameter can be any of the following:

  • Any member of type enumType.
  • A variable whose value is an enumeration member of type enumType.
  • The string representation of the name of an enumeration member. The characters in the string must have the same case as the enumeration member name.
  • A value of the underlying type of enumType.

I believe that's the reason why it has no overload and takes object as a second parameter. Since this method takes object as a second parameter - and object is a base class for all .NET types - you can pass string or int or etc..

Here how this method implemented;

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

And looks like this virtual Type.IsEnumDefined method handles all of these cases in it's implementation like;

    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);
        }
    }

Autres conseils

In the documentation for Enum.IsDefined it states that this value is

Type: System.Object

The value or name of a constant in enumType.

You have given Mercury the value of 5, therefore it is able to see this

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top