简体   繁体   中英

Why can't I cast an integer to an enumeration

I am trying to cast an integer from a DataGridViewRow cell value which I have confirmed equals 0

AddedTask.Status = (TaskStatus) row.Cells["status"].Value;

Visual Studio中的InvalidCastException

Here is the code that creates the Task object and the TaskStatus Enum.

class Task
{
    public string Description { get; set; }

    public TimeSpan Duration
    {
        get
        {
            if (BeginDate == DateTime.MinValue) // BeginDate has not been set
                return new TimeSpan(0, 0, 0);
            else if (EndDate == DateTime.MinValue)
                return DateTime.Now.Subtract(this.BeginDate);
            else
                return this.EndDate.Subtract(this.BeginDate);
        }
    }

    public DateTime BeginDate { get; set; }
    public DateTime EndDate { get; set; }
    public TaskStatus Status { get; set; }

    public Task()
    {
        this.Description = string.Empty;
        this.BeginDate = new DateTime();
        this.EndDate = new DateTime();
        this.Status = TaskStatus.UNINVOICED;
    }
}

public enum TaskStatus
{
    UNINVOICED,
    INVOICED,
    PAID
}

I tested around a little bit and observed that the cast succeeds if the original value is an Int32 but fails if it is (for example) an Int64 or a byte .

My suggestes solution is to use Convert.ToInt32() before the cast:

AddedTask.Status = (TaskStatus) Convert.ToInt32(row.Cells["status"].Value);

From docs.microsoft.com :

An enumeration is a set of named constants whose underlying type is any integral type. If no underlying type is explicitly declared, Int32 is used.

So your TaskStatus enum is derived from Int32 and direct casts from any other integral types will fail.

这可行,但是如果这是我可能要退休的C#的唯一方法。

AddedTask.Status = (TaskStatus) Enum.Parse(typeof(TaskStatus), row.Cells["status"].Value.ToString());

As a side note. When you work with enum's you should work with the string of that enum, when persisting or exposing via services.

var value = TaskStatus.UNINVOICED;
var x = value.ToString();

var reversed = (TaskStatus)Enum.Parse(typeof(TaskStatus), x);

The reason you want to persist that is so you can modify your enum in the future. If on Day 1 your enum looks like this:

public enum TaskStatus
{
    UNINVOICED,
    INVOICED,
    PAID
}

UNINVOICED may have an int value of 0, INVOICED may have a value of 1 and PAID may have a value of 2.

And then, if you need to update your enum to something like this:

public enum TaskStatus
{
    NOTSET,
    UNINVOICED,
    INVOICED,
    SOMEOTHERSTATUSBETWEENINVOICEDANDPAID,
    PAID
}

Then all your persisted data gets redefined, if done by int. What was once UNINVOICED will now translate to NOTSET, and what was once PAID is now INVOICED.

And if you expose your through a service interface, depending on the Technology it will assign int values of the enum elements differently.

That is to say, that the enum exposed through Web Reference will NOT have that same int value as the enum exposed through Service Reference .

Always, persist your enum as string and always pass it around / convert it by enum or by string.

As a more generic approach you can create custom method that will convert all numeric types to any enumeration type you need :

static TEnum GetEnum<TEnum>(object obj)
    where TEnum : struct, IConvertible
{
    if (!typeof(TEnum).IsEnum)
        throw new ArgumentException("TEnum must be an enumerated type");                

    return (TEnum)(IConvertible)(Convert.ToInt32(obj));
}

Simple example of its usage :

    enum Planet { Sun = 0, Moon = 1 }
    enum Abc { Abc5 = 0, Abc30 = 1 }

    private static void Main(string[] args)
    {
        var x = GetEnum<Planet>((long) 0);
        var y = GetEnum<Abc>((double)1);
        Console.Write(x);
        Console.Write(",  " + y);
    }

Output: Sun, Abc30

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM