【问题标题】:using Generics to Cast an Enum to Dictionary使用泛型将枚举转换为字典
【发布时间】:2013-02-23 23:56:41
【问题描述】:

我正在尝试创建一个我可以调用的方法,它将从枚举中返回一个 Dictionary<int,string> 类型的字典。

我想使用泛型。

这是我目前的代码...

public class Enums
{
    public static Dictionary<int, string> GetEnumDictionary<T>()
    {
        return Enum.GetValues(typeof(T)))
           .Cast<typeof(T)>()
           .ToDictionary(t => (int)t, t => t.ToString());
    }

    /// <summary>
    /// Fuel Type Enum
    /// </summary>
    public enum FuelTypes
    {
        Petrol = 1,
        Diesel = 2,
        Hybrid = 3,
        Electric = 4
    }
}

单元测试...

[TestClass]
public class EnumTests
{
    [TestMethod]
    public void TestGetEnumDictionary()
    {
        Dictionary<int, string> dict = new Dictionary<int, string>();
        dict = Enums.GetEnumDictionary<Enums.FuelTypes>();
        Assert.IsTrue(dict != null);
    }
}

我得到的编译错误是

运算符“

谁能看到我的错误在哪里?

【问题讨论】:

  • 看起来你没有发布你的实际代码。错误消息是关于 GetEnumDictionary(Type) 方法的,您没有发布。
  • 位于顶部 -> public static Dictionary GetEnumDictionary()
  • 那是另一种方法。错误消息涉及public static Dictionary&lt;int, string&gt; GetEnumDictionary(Type type) 或类似内容。
  • 是的,你的权利,我现在正在更新......

标签: c# linq generics


【解决方案1】:

GetEnumDictionary 方法中有两个主要错误:

首先,Cast&lt;typeof(T)&gt; 没有意义。就是Cast&lt;T&gt;

然后,您不能简单地将 T 类型的值转换为 int,而必须先将其转换为 object。
所以,你应该像这样改变你的方法:

public static Dictionary<int, string> GetEnumDictionary<T>()
{
    return Enum.GetValues(typeof(T))
       .Cast<T>()
       .ToDictionary(t => (int)(object)t, t => t.ToString());
}

但问题是你可以将任何你想要的类型传递给 T,甚至是非枚举类型。 不幸的是,您不能将泛型类型限制为 Enum,因此您需要在运行时检查它:

public static Dictionary<int, string> GetEnumDictionary<T>()
{
    if(!typeof(T).IsEnum)
       throw new ArgumentException("T is not an Enum type");
    return Enum.GetValues(typeof(T))
       .Cast<T>()
       .ToDictionary(t => (int)(object)t, t => t.ToString());
}

编辑:

正如 svick 正确指出的那样,枚举的基础类型可以不同于 int。 因此,例如,它不适用于像这样的枚举:

enum MyEnum : long
{
   Foo,
   Bar,
}

为了更安全,也许您还应该在运行时检查:

public static Dictionary<int, string> GetEnumDictionary<T>()
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T is not an Enum type");
    if (Enum.GetUnderlyingType(typeof(T)) != typeof(int))
        throw new ArgumentException("The underlying type of the enum T is not Int32");
    return Enum.GetValues(typeof(T))
        .Cast<T>()
        .ToDictionary(t => (int)(object)t, t => t.ToString());
}

最后一点。

您可以更改代码以支持具有适合Int32 的整数值的枚举。实际上,您可以简单地放置 Convert.ToInt32() 而不是使用直接转换为 int ,或者如其他答案中正确显示的那样,您可以利用 IConvertible 接口。
但是,在我看来,它并没有给你带来很多好处。由于此方法不是真正的类型安全,因此您应该在知道自己在做什么时使用它;因此,如果您想要一个“长枚举”中的字典(例如),只需使用/制作另一种方法......

【讨论】:

  • 注意这一点,它仅适用于具有int 基础类型的enums(尽管几乎所有enums 都这样做)。
  • 是的,你是对的,忘了它。我将在答案中提到它;)
【解决方案2】:

错误在这里:

.Cast<typeof(T)>()

您正在尝试使用 Type 类的实例作为泛型参数,您应该改用该类型:

.Cast<T>()

【讨论】:

  • 非常好,请注意我也改了 -> .ToDictionary(t => Convert.ToInt32(t), t => t.ToString());
【解决方案3】:

你可以这样做:

public static IDictionary<int, string> GetEnumDictionary<T>()
where T : IConvertible
{
    return Enum
       .GetValues(typeof(T))
       .Cast<T>()
       .ToDictionary(
           t => t.ToInt32(CultureInfo.InvariantCulture)
       ,   t => t.ToString()
       );
}

您的代码中有几个小问题:

  • Cast 应该是T,而不是typeof(T)
  • 禁止将T 转换为int,因此您需要使用enums 是IConvertible这一事实

这是一个快速的demo on ideone

【讨论】:

    猜你喜欢
    • 2019-02-27
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    • 1970-01-01
    • 2021-06-12
    • 1970-01-01
    相关资源
    最近更新 更多