Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why and how (internally) does Enum.IsDefined search for both name and value?

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?

like image 353
Farhad Jabiyev Avatar asked Apr 27 '14 09:04

Farhad Jabiyev


People also ask

Is enum a reference or value type?

An enum type is a distinct value type (§8.3) that declares a set of named constants. declares an enum type named Color with members Red , Green , and Blue .

What is enum method in C#?

Enums in C# The enum keyword in C# declares a list of named integer constants. An enum can be defined in a namespace, structure or class. However, it is better to define it in a namespace so that all the classes can access it.

What is enum in c# net with example?

In C#, an enum (or enumeration type) is used to assign constant names to a group of numeric integer values. It makes constant values more readable, for example, WeekDays. Monday is more readable then number 0 when referring to the day in a week.


2 Answers

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);
        }
    }
like image 68
Soner Gönül Avatar answered Oct 19 '22 23:10

Soner Gönül


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

like image 25
Sayse Avatar answered Oct 20 '22 01:10

Sayse