简体   繁体   English

为什么我不能将整数转换为枚举

[英]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 我正在尝试从已经确认等于0的DataGridViewRow单元格值强制转换为整数

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

Visual Studio中的InvalidCastException

Here is the code that creates the Task object and the TaskStatus Enum. 这是创建Task对象和TaskStatus枚举的代码。

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 . 我进行了一些测试,发现如果原始值是Int32 ,则转换成功,但如果原始值是Int64byte ,则转换失败。

My suggestes solution is to use Convert.ToInt32() before the cast: 我建议的解决方案是在Convert.ToInt32()之前使用Convert.ToInt32()

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

From docs.microsoft.com : 来自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. 如果未显式声明任何基础类型,则使用Int32。

So your TaskStatus enum is derived from Int32 and direct casts from any other integral types will fail. 因此,您的TaskStatus枚举是从Int32派生的,任何其他整数类型的直接强制转换都会失败。

这可行,但是如果这是我可能要退休的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: 如果在第1天您的枚举看起来像这样:

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. UNINVOICED的int值可以为0,INVOICED的值可以为1,PAID的值可以为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. 然后,如果由int完成,则所有保留的数据都将重新定义。 What was once UNINVOICED will now translate to NOTSET, and what was once PAID is now INVOICED. 曾经是UNINVOICED的现在将转换为NOTSET,而曾经是PAID的现在已转换为INVOICED。

And if you expose your through a service interface, depending on the Technology it will assign int values of the enum elements differently. 并且,如果您通过服务接口公开您的内容,则根据技术的不同,它将为枚举元素分配不同的int值。

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 . 也就是说,通过Web Reference公开的枚举不会具有与通过Service Reference公开的枚举相同的int值。

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 输出:Sun,Abc30

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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