C# 如何将通用枚举转换为 int?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16960555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:14:42  来源:igfitidea点击:

How do I cast a generic enum to int?

c#enums

提问by dotnetnoob

I have a small method that looks like this:

我有一个看起来像这样的小方法:

public void SetOptions<T>() where T : Enum
{
    int i = 0;
    foreach (T obj in Enum.GetValues(typeof(T)))
    {
        if (i == 0)
            DefaultOption = new ListItem(obj.Description(), obj.ToString());
        i++;
        DropDownList.Items.Add(new ListItem(obj.Description(), obj.ToString()));
    }
}

Basically, I populate a dropdown list from an enum. Description()is actually an extension method for enums, so Tis definitely an enum.

基本上,我从枚举填充下拉列表。Description()实际上是枚举的扩展方法,因此T绝对是enum.

However, I want to cast objjust as you would any enum to its index like this (int)obj, but I get an error saying I can't convert T to int. Is there a way to do this?

但是,我想像obj任何枚举一样将其转换为这样的索引(int)obj,但是我收到一条错误消息,说我无法将 T 转换为 int。有没有办法做到这一点?

采纳答案by petchirajan

try this,

尝试这个,

public void SetOptions<T>()
{
    Type genericType = typeof(T);
    if (genericType.IsEnum)
    {
        foreach (T obj in Enum.GetValues(genericType))
        {
            Enum test = Enum.Parse(typeof(T), obj.ToString()) as Enum;
            int x = Convert.ToInt32(test); // x is the integer value of enum
                        ..........
                        ..........
        }
    }
}

回答by zmbq

I'm surprised your code works at all. Enum.GetValuesreturns an array of integers - which are the values you're looking for. And, as others have mentioned, you can't constrain your generics to an enum.

我很惊讶你的代码完全有效。Enum.GetValues返回一个整数数组 - 这是您要查找的值。而且,正如其他人所提到的,您不能将泛型限制为 enum

Instead, you should probably call your Descriptionmethod as a regular static method and not an extension method.

相反,您可能应该将您的Description方法作为常规静态方法而不是扩展方法来调用。

回答by jan

Can you abuseGetHashCodefor this?

您可以为此滥用GetHashCode吗?

public enum MyEnum
{
  Foo = 100,
  Bar = 200,
  Fizz = 0
}

static void Main(string[] args)
{
  var i1 = MyEnum.Foo.GetHashCode();  // i1 = 100
  var i2 = MyEnum.Bar.GetHashCode();  // i2 = 200
  var i3 = MyEnum.Fizz.GetHashCode(); // i3 = 0
}

Please note: "GetHashCode()is by designuseful for only one thing: putting an object in a hash table. Hence the name." - E. Lippert

请注意:“GetHashCode()设计有用的只有一两件事:把一个物体在哈希表故名。” - E. 利珀特

回答by P. Avery

To expand on Jan's answer concerning generics and enum values:

扩展 Jan 关于泛型和枚举值的回答:

void MyFunc<T>(T value)
{
    Type t = typeof(T);
    if(t.IsEnum)
    {
        int valueAsInt = value.GetHashCode(); // returns the integer value
    }
}

回答by matk

Using LINQ this can be done elegantly:

使用 LINQ 这可以优雅地完成:

public static void SetOptions<T>(this DropDownList dropDownList)
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("Type must be an enum type.");
    }

    dropDownList.Items.AddRange(Enum
        .GetValues(typeof(T))
        .Cast<Enum>()
        .Select(x => new ListItem(x.ToString(), Convert.ToInt32(x).ToString()))
        .ToArray());
}

回答by Alex Zhukovskiy

This one is working with any underlying type

这个适用于任何基础类型

Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()))

When is it applicable? For example when you want add a value to SqlCommand, which converts enums to 0and you have to explicitly cast it to matching type. But we can write following extension:

什么时候适用?例如,当您想将一个值添加到 时SqlCommand,它将枚举转换为,0并且您必须将其显式转换为匹配类型。但是我们可以编写以下扩展名:

public static void AddEnum(this SqlParameterCollection parameters, string parameterName, Enum value)
{
    parameters.AddWithValue(parameterName, Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType())));
}

Which is doing everything for us.

这正在为我们做一切。

回答by Steve Lautenschlager

Here's a simpler way.

这里有一个更简单的方法。

Since Enum implements IConvertible we can use ToInt32(..).

由于 Enum 实现了 IConvertible,我们可以使用 ToInt32(..)。

int? value = (enumCandidate as IConvertible)?.ToInt32(CultureInfo.InvariantCulture.Numberformat);

Or if you'd like a general purpose method for generic enums:

或者,如果您想要通用枚举的通用方法:

public static int GetEnumValue<T>(T inputEnum) where T: struct, IConvertible
{
    Type t = typeof(T);
    if (!t.IsEnum)
    {
        throw new ArgumentException("Input type must be an enum.");
    }

    return inputEnum.ToInt32(CultureInfo.InvariantCulture.NumberFormat);

}

Or yet more general:

或者更一般的:

public static int GetEnumValue(object enumInput)
{
    Type t = enumInput.GetType();
    if (!t.IsEnum)
    {
        throw new ArgumentException("Input type must be an enum.");
    }

    return ((IConvertible)inputEnum).ToInt32(CultureInfo.InvariantCulture.NumberFormat);

}

回答by NtFreX

You could also cast your value to objectfirst and then to int.

您也可以将您的值转换为objectfirst ,然后转换为int

C# 7.3 and above

C# 7.3 及以上

With the Enumgeneric constraint.

Enum泛型约束。

public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
    => (int)(object)value;

Below C# 7.3

低于 C# 7.3

Without the Enumgeneric constraint.

没有Enum通用约束。

public static int EnumToInt<TValue>(this TValue value)  where TValue : struct, IConvertible
{
    if(!typeof(TValue).IsEnum)
    {
        throw new ArgumentException(nameof(value));
    }

    return (int)(object)value;
}


If your enum inherits from other types for example from bytethe cast to int will throw an InvalidCastException.

如果您的枚举继承自其他类型,例如从bytecast 到 int 将抛出一个InvalidCastException.

You could either check if the base type of the enum is an integer.

您可以检查枚举的基本类型是否为整数。

public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
{
    if (!typeof(int).IsAssignableFrom(Enum.GetUnderlyingType(typeof(TValue))))
        throw new ArgumentException(nameof(TValue));

    return (int)(object)value;
}

Or you if you use Convert.ToInt32it will use the IConvertibleinterface of int32 to convert the incompatible types.

或者你如果使用Convert.ToInt32它会使用IConvertibleint32的接口来转换不兼容的类型。

public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
    => Convert.ToInt32(value);

Just be aware the converting uintto intand signed/unsigned pairs can cause unintended behavior. (Boxing to IConvertibleand the converting is less performant than just unboxing.)

请注意,转换uintint和有符号/无符号对可能会导致意外行为。(装箱IConvertible和转换的性能不如拆箱。)



I recommend creating a method for each enum base type to ensure the correct result is returned.

我建议为每个枚举基本类型创建一个方法,以确保返回正确的结果。

回答by ejmarino

Try this: (assuming that the TEnum has a numeration from 0 to n)

试试这个:(假设 TEnum 的编号从 0 到 n)

public void SetOptions<TEnum>() where TEnum : Enum
{
    foreach (TEnum obj in Enum.GetValues(typeof(TEnum)))
    {
        var i = (int)(object)obj;
        if (i == 0) DefaultOption = new ListItem(obj.Description(), obj.ToString());
        DropDownList.Items.Add(new ListItem(obj.Description(), obj.ToString()));
    }
}

回答by ForeverZer0

If you are targeting .NET Core, you can utilize Unsafe.As<TFrom, TTo>in the System.Runtime.CompilerServicesnamespace, as explained on MSDN. The advantage here is there will be no boxing done, which is the only real performance cost in the other answers here.

如果您的目标是 .NET Core,则可以Unsafe.As<TFrom, TTo>System.Runtime.CompilerServices命名空间中使用,如MSDN 上所述。这里的优点是不会进行装箱,这是此处其他答案中唯一真正的性能成本。

private static int EnumToInt<TEnum>(TEnum enumValue) where TEnum : Enum
{
    return Unsafe.As<TEnum, int>(enumValue);
}

Note that this approach suffers from the safe issue as other existing answers do: there is not a guarantee that the given enum is a compatible inttype, which is likely the same reason this functionality is not baked-in. If you are using this approach internally where you can be sure that any enum passed to it is a compatible type, then this is likely the most efficient approach.

请注意,此方法与其他现有答案一样存在安全问题:无法保证给定的枚举是兼容int类型,这可能与此功能未内置的原因相同。如果您在内部使用这种方法,您可以确保传递给它的任何枚举都是兼容类型,那么这可能是最有效的方法。

Hereis a link to an issue on dotnet's GitHub page where where this issue was raised, and some of the developers elaborated a bit on this approach if you would like to learn more.

是 dotnet 的 GitHub 页面上提出此问题的问题的链接,如果您想了解更多信息,一些开发人员详细介绍了这种方法。