从C#中的枚举获取int值


1821

我有一堂课叫做Questions(复数)。在此类中,有一个名为Question(单数)的枚举,它看起来像这样。

public enum Question
{
    Role = 2,
    ProjectFunding = 3,
    TotalEmployee = 4,
    NumberOfServers = 5,
    TopBusinessConcern = 6
}

Questions该类中,我有一个get(int foo)函数为此返回一个Questions对象foo。有没有一种简单的方法可以从枚举中获取整数值,所以我可以做这样的事情Questions.Get(Question.Role)


31
对于另一种方法:cast-int-to-enum-in-c-sharp
nawfal

11
我知道我迟到了,但不是定义你的方法get(int foo),你可以将它定义为get(Question foo)然后执行方法内的铸造,你可以打电话给你的方法Questions.Get(Question.Role)

Answers:


2350

只是枚举枚举,例如

int something = (int) Question.Role;

上面的代码适用于您在野外看到的绝大多数枚举,因为枚举的默认基础类型是int

但是,正如cecilphillip指出的那样,枚举可以具有不同的基础类型。如果枚举被声明为uintlong,或ulong,应当投射到枚举的类型; 例如

enum StarsInMilkyWay:long {Sun = 1, V645Centauri = 2 .. Wolf424B = 2147483649};

你应该使用

long something = (long)StarsInMilkyWay.Wolf424B;

23
@哈里这不是真的。您可以创建不强制转换的枚举,这不是必需的。而且我只会在特殊情况下分配编号,在大多数情况下,我会将其保留为默认值。但是您可以做到,enum Test { Item = 1 }并且发现那1 == (int)Test.Item是平等的。
贾德

33
@Jaider (int)Test.Item那是演员!()是显式强制转换运算符。
Sinthia V'7

48
@Sinthia V他说您可以无需铸造就可以创建它,这是正确的
Paul Ridgway 2012年

7
如果for的基础类型enum Question不是,intlong此强制转换将截断Roles的整数值!
quaylar

1
当接受a Enum作为参数时,您知道只能获得固定数量的可能的整数值。另一方面,如果仅使用一个int,则必须验证int该值是否在可接受的值之内,从而使代码复杂化。您始终可以覆盖签名,例如```public void MyMethod(int x){//用x做某事} public void MyMethod(Enum x){this.MyMethod((int)x); }``
percebus

307

由于枚举可以是任何整数类型(byteintshort等),更鲁棒的方式来获得的枚举的基本积分值将是使使用的GetTypeCode方法与结合Convert类:

enum Sides {
    Left, Right, Top, Bottom
}
Sides side = Sides.Bottom;

object val = Convert.ChangeType(side, side.GetTypeCode());
Console.WriteLine(val);

无论基础整数类型如何,这都应该起作用。


32
当处理T:enum(实际上是T:struct,IConvertible,但这是另一回事)的泛型类型时,这项技术对我来说是值得的。
2011年

1
您将如何修改它以打印出side的十六进制值?本示例显示了十进制值。问题是,该var类型为object,因此您需要将其拆箱,并且它变得比我想要的更混乱。
Mark Lakata 2012年

2
我想你应该的例子改变object val = Convert...etcvar你的榜样将永远是object
2013年

2
@TimAbell我真正能说的是,我们发现动态编译的aspx页(您必须在其中将.cs文件部署到活动服务器中)将整数分配给每个值。这意味着一台机器上的序列化对象在另一台机器上以不同的值进行反序列化,并有效地被破坏(造成数小时的混乱)。我们用MS提出的,我似乎还记得他们说过,跨不同框架版本构建时,不能保证自动生成的整数是相同的。
NickG 2015年

4
@TimAbell在另一个情况下,开发人员删除了一个过时的/未使用的Enum值,导致序列中的所有其他值都被一个掉了。因此,我们的编码标准现在要求始终明确指定ID,否则添加/删除甚至自动格式化代码(例如,按字母顺序排序)将更改所有值,从而导致数据损坏。我强烈建议任何人明确指定所有Enum整数。如果它们与外部(数据库)存储的值相关联,则这非常重要。
NickG 2015年

199

将其声明为具有公共常量的静态类:

public static class Question
{
    public const int Role = 2;
    public const int ProjectFunding = 3;
    public const int TotalEmployee = 4;
    public const int NumberOfServers = 5;
    public const int TopBusinessConcern = 6;
}

然后,您可以将其引用为Question.Role,并且它始终求值为int或您定义为的任何值。


31
static readonly int之所以使用,是因为常量被编译为硬值。参见stackoverflow.com/a/755693/492
CAD bloke

96
该解决方案实际上并未提供强类型枚举的真正好处。例如,如果我只想将GameState-enum-parameter传递给特定方法,则编译器不应允许我将任何int变量作为参数传递。
thgc

12
@CADBloke恰好是您使用@CADBloke的原因,const而不是static readonly因为每次进行比较时,static readonly您都在进行方法调用以获取变量的值,而使用a时,const您将直接比较两种值类型。
blockloop

3
@ brettof86是的,一个const会更快,如果编译限制永远不会成为问题,那么一切都很好。
CAD笨拙

2
@Zack我的解释不是很好,因为compilation limitation我的意思是编译该值时会对该值进行硬编码,因此对该值的任何更改都将需要重新编译使用该值的所有程序集。对于用法,我倾向于同意您的意见,因为更改值将产生深远的影响。
CAD bloke'Apr

87
Question question = Question.Role;
int value = (int) question;

将导致value == 2


34
临时变量问题是不必要的。
Gishu 2009年

1
像这样的问题Questions.Get(Convert.ToInt16(Question.Applications))
吉姆

6
您可以简单地向任一方向投射;唯一要注意的是枚举不执行任何操作(即使该数字不存在任何问题,枚举值也可以为288)
Marc Gravell

@jim:不,只需将值强制转换为:Questions.Get((int)Question.Applications);
Guffa

1
@Gishu你可以说这是...值得怀疑的。;)
Felix D.

79

与此相关的是,如果您想从中获取intSystem.Enum,请e在此处给出:

Enum e = Question.Role;

您可以使用:

int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);

最后两个很丑陋。我喜欢第一个。


1
第二个是最快的。
Johan B

1
作为习惯在Minecraft改装中使用Mixins的人,第二个似乎是显而易见的赢家。
Sollace

40

比您想象的要容易-枚举已经是一个int。它只需要提醒:

int y = (int)Question.Role;
Console.WriteLine(y); // Prints 2

15
Nitpick:枚举已经是一个int。其他枚举可能是不同的类型-尝试“枚举SmallEnum:字节{A,B,C}”
mqp,2009年

9
千真万确。C#参考:“每个枚举类型都有一个基础类型,可以是除char之外的任何整数类型。”
Michael Petrotta 09年

33

例:

public Enum EmpNo
{
    Raj = 1,
    Rahul,
    Priyanka
}

并在后面的代码中获取枚举值:

int setempNo = (int)EmpNo.Raj; // This will give setempNo = 1

要么

int setempNo = (int)EmpNo.Rahul; // This will give setempNo = 2

枚举将增加1,您可以设置起始值。如果不设置起始值,则初始值将被分配为0。


6
这实际上可以编译吗?
Peter Mortensen

拉杰(Rajul)或普里扬卡(Priyanka)可以是拉吉(Rahul)还是普里扬卡(Priyanka)吗?您的值冲突,应该加倍以使其唯一,例如0、1、2、4、8等。这是枚举的核心问题。
蒂莫西·冈萨雷斯

@TimothyGonzalez实际上只是枚举1,如果您没有明确指定它们的值;)
derHugo

@derHugo如果假设的数值为基座10或基座2依赖
蒂莫西·冈萨雷斯

@TimothyGonzalez没什么好假设的...我只是指出,默认情况下,它们只会累加1int除非您明确定义否则
derHugo

28

最近,我不再使用代码中的枚举,而是改为使用具有受保护的构造函数和预定义的静态实例的类(这要归功于Roelof- C#确保有效的枚举值-Futureproof方法)。

有鉴于此,以下是我现在如何解决此问题的方法(包括隐式转换为或从转换为int)。

public class Question
{
    // Attributes
    protected int index;
    protected string name;
    // Go with a dictionary to enforce unique index
    //protected static readonly ICollection<Question> values = new Collection<Question>();
    protected static readonly IDictionary<int,Question> values = new Dictionary<int,Question>();

    // Define the "enum" values
    public static readonly Question Role = new Question(2,"Role");
    public static readonly Question ProjectFunding = new Question(3, "Project Funding");
    public static readonly Question TotalEmployee = new Question(4, "Total Employee");
    public static readonly Question NumberOfServers = new Question(5, "Number of Servers");
    public static readonly Question TopBusinessConcern = new Question(6, "Top Business Concern");

    // Constructors
    protected Question(int index, string name)
    {
        this.index = index;
        this.name = name;
        values.Add(index, this);
    }

    // Easy int conversion
    public static implicit operator int(Question question) =>
        question.index; //nb: if question is null this will return a null pointer exception

    public static implicit operator Question(int index) =>        
        values.TryGetValue(index, out var question) ? question : null;

    // Easy string conversion (also update ToString for the same effect)
    public override string ToString() =>
        this.name;

    public static implicit operator string(Question question) =>
        question?.ToString();

    public static implicit operator Question(string name) =>
        name == null ? null : values.Values.FirstOrDefault(item => name.Equals(item.name, StringComparison.CurrentCultureIgnoreCase));


    // If you specifically want a Get(int x) function (though not required given the implicit converstion)
    public Question Get(int foo) =>
        foo; //(implicit conversion will take care of the conversion for you)
}

这种方法的优点是您可以从枚举中获得所有内容,但是您的代码现在更加灵活,因此,如果需要根据的值执行不同的操作Question,则可以将逻辑放入Question自身(即,在首选的OO中)时尚),而不是在整个代码中放置大量case语句来解决每种情况。


注意:答案已于2018-04-27更新,以利用C#6功能; 即声明表达式和lambda表达式主体定义。有关原始代码,请参见修订历史记录。这样做的好处是使定义不再那么冗长。这是对该答案方法的主要抱怨之一。


2
我想这是在显式强制转换和必须编写的代码之间进行权衡的方法。仍然喜欢该实现,只是希望它没有那么长。+1
Lankymart

3
我使用了几种与此类似的不同类型的类。我发现当尝试遵循“以后不要让我成为白痴”方法时,他们会产生奇迹。
詹姆斯·豪格

20

如果要获取存储在变量中的枚举值的整数(该类型的类型为)Question,例如要在方法中使用,则可以简单地执行我在此示例中编写的操作:

enum Talen
{
    Engels = 1, Italiaans = 2, Portugees = 3, Nederlands = 4, Duits = 5, Dens = 6
}

Talen Geselecteerd;    

public void Form1()
{
    InitializeComponent()
    Geselecteerd = Talen.Nederlands;
}

// You can use the Enum type as a parameter, so any enumeration from any enumerator can be used as parameter
void VeranderenTitel(Enum e)
{
    this.Text = Convert.ToInt32(e).ToString();
}

这将把窗口标题更改为4,因为变量GeselecteerdTalen.Nederlands。如果将其更改为Talen.Portugees并再次调用该方法,则文本将更改为3。


3
在荷兰编码。噢亲爱的。
WiseStrawberry

不幸的是,这种方法使用得越多,性能就会越差。我用我的一些代码尝试了一下,随着时间的流逝,我的应用程序变得越来越慢,CPU使用率越来越少。这暗示着线程正在等待某些东西-我假设某种垃圾回收,可能是由于将Toumt32()的枚举参数装箱了。通过切换到简单的int.Parse(),我可以完全消除这种不良的性能,并且无论代码运行多长时间,性能都保持不变。
格雷格

16

要确保存在枚举值然后进行解析,您还可以执行以下操作。

// Fake Day of Week
string strDOWFake = "SuperDay";

// Real Day of Week
string strDOWReal = "Friday";

// Will hold which ever is the real DOW.
DayOfWeek enmDOW;

// See if fake DOW is defined in the DayOfWeek enumeration.
if (Enum.IsDefined(typeof(DayOfWeek), strDOWFake))
{
    // This will never be reached since "SuperDay"
    // doesn't exist in the DayOfWeek enumeration.
    enmDOW = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), strDOWFake);
}
// See if real DOW is defined in the DayOfWeek enumeration.
else if (Enum.IsDefined(typeof(DayOfWeek), strDOWReal))
{
    // This will parse the string into it's corresponding DOW enum object.
    enmDOW = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), strDOWReal);
}

// Can now use the DOW enum object.
Console.Write("Today is " + enmDOW.ToString() + ".");

14

也许我错过了,但是有人尝试过一种简单的通用扩展方法吗?

这对我来说很棒。您可以通过这种方式避免在API中进行类型转换,但最终会导致更改类型操作。这是对Roslyn进行编程以使编译器为您创建GetValue <T>方法的一个很好的例子。

    public static void Main()
    {
        int test = MyCSharpWrapperMethod(TestEnum.Test1);

        Debug.Assert(test == 1);
    }

    public static int MyCSharpWrapperMethod(TestEnum customFlag)
    {
        return MyCPlusPlusMethod(customFlag.GetValue<int>());
    }

    public static int MyCPlusPlusMethod(int customFlag)
    {
        // Pretend you made a PInvoke or COM+ call to C++ method that require an integer
        return customFlag;
    }

    public enum TestEnum
    {
        Test1 = 1,
        Test2 = 2,
        Test3 = 3
    }
}

public static class EnumExtensions
{
    public static T GetValue<T>(this Enum enumeration)
    {
        T result = default(T);

        try
        {
            result = (T)Convert.ChangeType(enumeration, typeof(T));
        }
        catch (Exception ex)
        {
            Debug.Assert(false);
            Debug.WriteLine(ex);
        }

        return result;
    }
}

可能是因为执行(int)customFlag较少在各处键入内容,或多或少是同一件事?
Tim Keating 2014年

关于“也许我错过了,但是有人尝试过一种简单的通用扩展方法吗?” SixOThree说 “ 改为使用扩展方法 ”,Bronek说 “可以通过对定义的枚举类型实现扩展方法来做到这一点”
彼得·莫滕森

13

另一种方法是:

Console.WriteLine("Name: {0}, Value: {0:D}", Question.Role);

它将导致:

Name: Role, Value: 2

12
public enum QuestionType
{
    Role = 2,
    ProjectFunding = 3,
    TotalEmployee = 4,
    NumberOfServers = 5,
    TopBusinessConcern = 6
}

...是一个很好的声明。

您必须将结果强制转换为int,如下所示:

int Question = (int)QuestionType.Role

否则,类型仍为QuestionType

这种严格程度是C#方式。

一种替代方法是改为使用类声明:

public class QuestionType
{
    public static int Role = 2,
    public static int ProjectFunding = 3,
    public static int TotalEmployee = 4,
    public static int NumberOfServers = 5,
    public static int TopBusinessConcern = 6
}

声明起来不太优雅,但是您无需将其强制转换为代码:

int Question = QuestionType.Role

另外,您可能对Visual Basic感到更自在,Visual Basic在许多方面都可以满足这种期望。


11
int number = Question.Role.GetHashCode();

number应该具有价值2


GetHashCode是从枚举通用掩码中获取价值的一种方法
ThanhLD

请注意,这是唯一的“合法” bool*, ,byteushortintuint**。其他类型的GetHashCode会修改值,例如,进行一些移位和异或。(* 1/0,当然是**转换为int)。但总的来说,除非是您自己的私人代码,否则请不要这样做。
AnorZaken

10

您可以通过对定义的枚举类型实现扩展方法来做到这一点:

public static class MyExtensions
{
    public static int getNumberValue(this Question questionThis)
    {
        return (int)questionThis;
    }
}

这简化了获取当前枚举值的int值的操作:

Question question = Question.Role;
int value = question.getNumberValue();

要么

int value = Question.Role.getNumberValue();

5
Bronek,您所做的是通过(非通用btw)扩展方法弥补了信息性语法的不足,而该扩展方法实际上需要花费更长的时间来编写。我看不出它比Tetraneutron的原始解决方案更好。让我们不要聊天,在stackoverflow中总是欢迎提供帮助,这里的每个人都在这里提供帮助。请把我的评论视为建设性批评。
Benjamin Gruenbaum 2012年

2
本杰明,首先,您为什么删除我的评论?我不理解您的决定-也许社区中的其他人也会同意我的评论。其次,我的解决方案将Tetraneutron的解决方案包裹了起来,准确地说,它更容易写,而且写得更少,因为扩展方法是由IntelliSense建议的。因此,我认为您的决定并不公正且不具有代表性。我在Stack上看到许多类似的答案,也可以。无论如何,我使用我的解决方案,也许将来有人会选择我的解决方案,但是这些负面因素使我们很难找到。所有这些都是正确的,不能复制。
Bronek

3
@Bronek如果您不对我执行ping操作,则不会显示您已答复。我并没有删除您的评论我没有能力或想这样做。可能有一个mod被删除了-欢迎您对其进行标记以引起主持人的注意,并询问原因或更好的方法-关于Meta Stack Overflow的问题。从编程的角度来看,我对您的解决方案有一种完全正确的看法-这就是注释的开头,无需个人化。
本杰明·格伦鲍姆

8

改用扩展方法:

public static class ExtensionMethods
{
    public static int IntValue(this Enum argEnum)
    {
        return Convert.ToInt32(argEnum);
    }
}

用法也更漂亮:

var intValue = Question.Role.IntValue();

7
public enum Suit : int
{
    Spades = 0,
    Hearts = 1,
    Clubs = 2,
    Diamonds = 3
}

Console.WriteLine((int)(Suit)Enum.Parse(typeof(Suit), "Clubs"));

// From int
Console.WriteLine((Suit)1);

// From a number you can also
Console.WriteLine((Suit)Enum.ToObject(typeof(Suit), 1));

if (typeof(Suit).IsEnumDefined("Spades"))
{
    var res = (int)(Suit)Enum.Parse(typeof(Suit), "Spades");
    Console.Out.WriteLine("{0}", res);
}

西装 - “ 10.(纸牌游戏)一包纸牌中的每套都以颜色和/或特定标志来区分,例如黑桃,心形,钻石或传统的盎格鲁,西班牙和法国扑克牌的棍棒。”
彼得·莫滕森

示例代码的解释应有条理(通过编辑答案,而不是在注释中)。
彼得·莫滕森

枚举通常为枚举的未设置/未知状态保留零,这是不寻常的定义
Chad Grant

6

采用:

Question question = Question.Role;
int value = question.GetHashCode();

它将导致value == 2

仅当枚举适合于时,这才是正确的int


1
仅当枚举适合于in时,这才是正确的int,因为GetHashCode返回整数。
RB。

5

由于可以用多种基本类型声明枚举,所以泛型转换任何枚举类型的通用方法可能会很有用。

enum Box
{
    HEIGHT,
    WIDTH,
    DEPTH
}

public static void UseEnum()
{
    int height = Box.HEIGHT.GetEnumValue<int>();
    int width = Box.WIDTH.GetEnumValue<int>();
    int depth = Box.DEPTH.GetEnumValue<int>();
}

public static T GetEnumValue<T>(this object e) => (T)e;

4

以下是扩展方法

public static string ToEnumString<TEnum>(this int enumValue)
{
    var enumString = enumValue.ToString();
    if (Enum.IsDefined(typeof(TEnum), enumValue))
    {
        enumString = ((TEnum) Enum.ToObject(typeof (TEnum), enumValue)).ToString();
    }
    return enumString;
}

4

我最喜欢的带有int或更小的枚举的hack:

GetHashCode();

对于一个枚举

public enum Test
{
    Min = Int32.MinValue,
    One = 1,
    Max = Int32.MaxValue,
}

这个,

var values = Enum.GetValues(typeof(Test));

foreach (var val in values)
{
    Console.WriteLine(val.GetHashCode());
    Console.WriteLine(((int)val));
    Console.WriteLine(val);
}

输出

one
1
1
max
2147483647
2147483647
min
-2147483648
-2147483648

免责声明:

它对于基于长枚举的枚举不起作用。


3

我能想到的最简单的解决方案是重载这样的Get(int)方法:

[modifiers] Questions Get(Question q)
{
    return Get((int)q);
}

其中[modifiers]通常可以是相同的Get(int)方法。如果您无法编辑Questions该类或由于某种原因而不想这样做,则可以通过编写扩展来重载该方法:

public static class Extensions
{
    public static Questions Get(this Questions qs, Question q)
    {
        return qs.Get((int)q);
    }
}

3

我想建议“从枚举中获取'int'值”的示例是

public enum Sample
{
    Book = 1, 
    Pen = 2, 
    Pencil = 3
}

int answer = (int)Sample.Book;

现在答案是1。




2

在Visual Basic中,它应该是:

Public Enum Question
    Role = 2
    ProjectFunding = 3
    TotalEmployee = 4
    NumberOfServers = 5
    TopBusinessConcern = 6
End Enum

Private value As Integer = CInt(Question.Role)

3
问题是针对C#的。
Ctrl S

2
标题说“从C#中的枚举获取int值”
彼得·莫滕森

0

我想出了这种扩展方法,其中包括当前的语言功能。通过使用动态,我不需要使它成为通用方法并指定使调用更简单和一致的类型:

public static class EnumEx
{
    public static dynamic Value(this Enum e)
    {
        switch (e.GetTypeCode())
        {
            case TypeCode.Byte:
            {
                return (byte) (IConvertible) e;
            }

            case TypeCode.Int16:
            {
                return (short) (IConvertible) e;
            }

            case TypeCode.Int32:
            {
                return (int) (IConvertible) e;
            }

            case TypeCode.Int64:
            {
                return (long) (IConvertible) e;
            }

            case TypeCode.UInt16:
            {
                return (ushort) (IConvertible) e;
            }

            case TypeCode.UInt32:
            {
                return (uint) (IConvertible) e;
            }

            case TypeCode.UInt64:
            {
                return (ulong) (IConvertible) e;
            }

            case TypeCode.SByte:
            {
                return (sbyte) (IConvertible) e;
            }
        }

        return 0;
    }

请否,您可以在一行中完成所有这些操作Convert.Changetype(e,e.GetTypeCode())并获取对象,无需动力学或扩展方法
Chad Grant

我不同意使用Convert。仅使用演员表会更容易。我的意图是能够在不使用强制转换的情况下将任何枚举转换为其值。这允许更改枚举类型而不必更改所有关联的强制类型转换-但是什么时候发生?扩展方法可以正常工作。但是,我有一个问题,因为它是动态的,所以编译器无法进行类型检查(显然对于整个语句),这意味着在运行时进行类型检查-不是一个好的解决方案。我想我会回到演员表。
杰夫

1
我并不是说要在强制转换中使用它,只是因为这段代码是荒谬的,什么也不做,实际上使问题变得更糟。我建议删除此解决方案
乍得·格兰特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.