关于C#:枚举作为方法中的参数,通过枚举循环产生无效的强制转换


Enum as a parameter in a method, looping through the enum produces invalid cast

这就是我所拥有的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    private IEnumerable<SelectListItem> GetAllEnumValues(Enum enumValues)
    {
        var allEnumValues = new List<SelectListItem>();
        var values = Enum.GetValues(enumValues.GetType());
        foreach (var selectedItem in values)
        {
            allEnumValues.Add(new SelectListItem
                                  {
                                      Value = ((int)selectedItem).ToString(),
                                      Text = selectedItem.ToString()
                                  });
        }

        return allEnumValues.AsEnumerable();
    }

方法的调用方式如下:

1
AllAgencies = GetAllEnumValues((AgencyCodes) 0)

构建很好,但是当实际使用该方法时,我得到"指定的强制转换无效"。死亡的黄色屏幕在.add行上。我需要selectListItem的值是实际的枚举数,只是强制转换为字符串。到目前为止,我尝试了所有这些方法:C遍历枚举?(索引System.Array)、C和ForEach中的枚举,如何枚举枚举?最后,我总是以同样的错误结束。我正在使用.NET 4.0。


这通常意味着您的枚举不是基于int,例如:

1
2
3
enum AgencyCodes : short {
    ...
}

不能将枚举取消绑定到错误的值类型。


如果需要数值,可以使用Convert.ToInt32(selectedItem),然后对其执行ToString()。如果enum是基于int的。(从技术上讲,除非enum的值对int来说太大,否则它将起作用)

现在,多亏了表情树的魔力…两类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public static class EnumToString<T>
{
    public static readonly Func<T, string> Do;

    static EnumToString()
    {
        Type type = typeof(T);

        if (!type.IsEnum)
        {
            throw new ArgumentException();
        }

        Type baseType = type.GetEnumUnderlyingType();

        var par1 = Expression.Parameter(typeof(T));

        var cast = Expression.Convert(par1, baseType);

        Expression<Func<object, string>> toString = p => p.ToString();
        var body = (MethodCallExpression)toString.Body;

        var toString2 = Expression.Call(cast, body.Method);

        Do = Expression.Lambda<Func<T, string>>(toString2, par1).Compile();
    }
}

public static class EnumToObject<T>
{
    public static readonly Func<T, object> Do;

    static EnumToObject()
    {
        Type type = typeof(T);

        if (!type.IsEnum)
        {
            throw new ArgumentException();
        }

        Type baseType = type.GetEnumUnderlyingType();

        var par1 = Expression.Parameter(typeof(T));

        var cast1 = Expression.Convert(par1, baseType);
        var cast2 = Expression.Convert(cast1, typeof(object));

        Do = Expression.Lambda<Func<T, object>>(cast2, par1).Compile();
    }
}

static void Main()
{
    string str = EnumToString<MyEnum>.Do(MyEnum.Foo); //"1"
    object obj = EnumToObject<MyEnum>.Do(MyEnum.Foo); // (int)1
}

第一个,EnumToString<>获取枚举值的值并将其转换为字符串。第二个函数将枚举值的值转换为它的基类型(无论它是什么),并返回一个object(因此它将基值框起来)(例如,您可以在基值框中执行.ToString())。

要使用它们,您必须将类更改为如下类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
IEnumerable<SelectListItem> GetAllEnumValues<T>()
{
    // In truth, the array returned by Enum.GetValues **is** strongly typed
    // but is"downcasted" to Array. So we re-upcast it.
    T[] values = (T[])Enum.GetValues(typeof(T));
    ...

        Value = EnumToString<T>.Do(selectedItem),

        // or

        Value = EnumToObject<T>.Do(selectedItem).ToString(),
}

但请注意,所有这些几乎都是无用的,因为有一个特殊的格式化程序d

1
2
3
4
5
MyEnum enu = MyEnum.Something; // (where MyEnum.Something == 1)
string str = enu.ToString("d"); // 1

Enum enu2 = enu;
string str2 = enu2.ToString("d"); // 1

请参见枚举格式字符串


根据你提供的信息,我怀疑

1
Value = ((int)selectedItem).ToString()

导致了你的问题。应该是

1
Value = (int)selectedItem; //if you need number and value is of type int

1
Value = selectedItem.ToString(); //if you need text and value is of type string