无法将类型'TEnum'转换为'int'

4

我正在尝试将枚举类型转换为列表,就像这个例子中所提到的一样。

Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Select(v => new SelectListItem {
    Text = v.ToString(),
    Value = ((int)v).ToString()
}).ToList();

这个代码可以工作,但我想修改它以兼容通用枚举

public static List<SelectListItem> GetEnumList<TEnum>(TEnum value)
{

        return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Select(v => new SelectListItem
        {
            Text = v.ToString(),
            Value = ((int)v).ToString()
        }).ToList();
 }

然而,上述代码无法编译并给出以下错误信息:

无法将类型'TEnum'转换为'int'

该错误出现在以下代码行:
  Value = ((int)v).ToString()
  1. 我该如何修复上面的代码。

  2. 为什么使用泛型枚举会产生编译错误,而使用普通枚举不会。


编辑:我已经尝试了帖子中的建议,但是我得到了进一步的错误:

这是我的完整代码:

public static IHtmlContent EnumDropDownListFor<TModel, TResult,TEnum>(
    this IHtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TResult>> expression,
    TEnum enumValue,
    string optionLabel) 
{
    return htmlHelper.DropDownListFor(expression, (IEnumerable<SelectListItem>)GetEnumList(enumValue), optionLabel);
}

public static List<SelectListItem> GetEnumList<TEnum>(TEnum value) 
{
    return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Select(v => new SelectListItem
    {
        Text = v.ToString(),
        Value = Convert.ToInt32(v).ToString()
    }).ToList();

}

但是我遇到了一个运行时错误

ArgumentException: 提供的类型必须是枚举。

参数名称:enumType

在这一行上:

return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Select(v => new SelectListItem
    {
        Text = v.ToString(),
        Value = Convert.ToInt32(v).ToString()
    }).ToList();

我需要在代码中修复什么问题,才能避免运行时错误?

你是想将枚举表示的整数赋值给Value属性吗? - Bruno Joaquim
https://dev59.com/DWsz5IYBdhLWcg3wADS6 - M.kazem Akhgary
首先将TEnum转换为枚举。 - Rik
重要的是 Ivan 的回答中的 where ... 子句。将其添加到您的方法中:EnumDropDownListFor(...) where .... - Marc
5个回答

6
您没有告诉编译器TEnum的任何信息。在编译器看来,它可以是一个字符串、日期时间、银行账户、子弹或其他任何东西。
要使其工作,您可以使用Enum.ParseConvert.ToInt32
更新:让我格式化一下评论中的代码并为SO复制粘贴者修复编译错误 :D
public static int GetEnumIntValue<T>(T value)
    where T : struct
{
    Type genericType = typeof(T);
    Debug.Assert(genericType.IsEnum);
    Enum enumValue = Enum.Parse(genericType, value.ToString()) as Enum;
    return Convert.ToInt32(enumValue);
}

你能提供一个在代码示例中使用Enum.Parse的例子吗? - zoaz
1
公共静态整数获取枚举值<T>(T value) where T : struct { Type genericType = typeof(T); Debug.Assert(genericType.IsEnum); Enum enumValue = Enum.Parse(typeof(T), value.ToString()) as Enum; return Convert.ToInt32(enumValue); } 你稍微搜索一下就能找到这个。 - Colin Grealy
感谢@ColinGrealy!让我来格式化您的代码并为SO-copy-pasters修复编译错误:D(请参见编辑后的答案) - moudrick

4
你不需要一个值,只需要枚举类型。你可以使用类似这样的代码:

通用

public static List<SelectListItem> GetEnumList<TEnum>()
    where TEnum : struct, IConvertible, IFormattable
{
    return ((TEnum[])Enum.GetValues(typeof(TEnum))).Select(v => new SelectListItem
    {
        Text = v.ToString(),
        Value = v.ToString("d", null)
    }).ToList();
}

非通用的

public static List<SelectListItem> GetEnumList(Type enumType)
{
    return Enum.GetValues(enumType).Cast<IFormattable>().Select(v => new SelectListItem
    {
        Text = v.ToString(),
        Value = v.ToString("d", null)
    }).ToList();
}

这两种方法都不是编译时类型安全的。泛型方法,因为缺少枚举约束。非泛型方法 - 嗯,它类似于 Enum 的静态方法,无论如何都不是编译时类型安全的。如果这两种方法使用非枚举类型调用,都会抛出运行时异常。


非泛型方法不是编译时安全的,因为任何类型都可以传递给该方法,包括非枚举类型。 - ASh
@Ash 正确,但对于通用方法也是如此,因为缺少枚举约束。如果未使用枚举类型调用,则两者都可能引发运行时异常。这与Enum方法类似。 - Ivan Stoev
如果我使用通用方式,只要我添加了“where TEnum:struct,IConvertible,IFormattable”的where子句,我的代码就无法编译。 错误CS0453:“Type”类型必须是非空值类型,才能将其用作参数“TEnum”的泛型类型或方法“MyHelperClass.GetEnumList <TEnum>(TEnum)”中的参数。 - zoaz
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Ivan Stoev
当我在调用方法和被调用的方法中都添加where子句时,我会收到该错误消息。 - zoaz
@ozdev,你可能有另一个通用方法调用了你的方法。所有涉及到的通用方法的类型约束必须相同。这就是为什么我提供了非通用版本 - 你可以像这样从你的 EnumDropDownListFor 中使用它(不需要放置约束):GetEnumList(typeof(TEnum)) - Ivan Stoev

1
public static List<SelectListItem> GetEnumList<TEnum>(TEnum value) where TEnum : IConvertible
{
    return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Select(v => new SelectListItem
    {
        Text = v.ToString(),
        Value = v.ToInt32(null).ToString()
    }).ToList();
}
  1. 编译器知道你在使用.Cast<MyEnum>()后的枚举类型。
  2. 但是在.Cast<TEnum>()之后,编译器不知道可能的类型。

我尝试了这段代码,但是出现了一个更进一步的错误:"提供的类型必须是枚举类型"。 - zoaz

1
编译器报错,因为泛型方法中的类型参数没有受到限制。此外,该方法不必是泛型的。
public static List<SelectListItem> GetEnumList(Enum value)
{
    return Enum.GetValues(value.GetType())
            .Cast<Enum>()
            .Select(v => new SelectListItem
                        {
                            Text = v.ToString(),
                            Value = Convert.ToInt32(v).ToString()
                        })
            .ToList();
}

这里仍可能存在问题,如果枚举的基础类型不是int

public enum LongEnum: ulong
{
    A = 0,
    B = 3000000000
}

// Run-time exception: Value was either too large or too small for an Int32.

当然 - 我并不是在攻击答案,只是为了未来的读者留下评论,如果他们偶然发现它。实际上,没有一种干净的方法可以做到 OP 想要的事情,因此每种方法都有其缺点。 - Rob
2
对于 ulong,你可以使用以下代码解决问题:Value = Convert.ChangeType(v, Enum.GetUnderlyingType(value.GetType())).ToString() :) - Rob
@Rob,感谢您宝贵的评论。我测试了您的建议,结果符合预期。 - ASh
@ozdev,我看了你的编辑,似乎你正在尝试另一个建议而不是我的。我建议使用非泛型方法。 - ASh
@ozdev,当我尝试使用@Html.EnumDropDownListFor(m=>m.MyValue, Model.MyValue, "")时,下拉菜单出现了。 - ASh
显示剩余6条评论

0

这是对我有效的方法, 扩展方法:

public static List<IdNameDto> ToIdNameList<TEnum>(this TEnum @enum) where TEnum : Enum
{
    return Enum.GetValues(typeof(TEnum)).Cast<TEnum>()
        .Select(x => new IdNameDto
        {
            Id = Convert.ToInt32(x),
            Name = x.ToString(),
        }).ToList();
}

dto :

public class IdNameDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

更新了答案,它所做的只是在枚举值中添加空格。 - Uttam Ughareja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接