【问题标题】:Method parameter with strongly typed Enum type具有强类型 Enum 类型的方法参数
【发布时间】:2010-09-25 19:11:23
【问题描述】:

考虑下面的代码

enum HorizontalAlignment { Left, Middle, Right };
enum VerticleAlignment { Top, Middle, Bottom };

function OutputEnumValues (Type enumType)
{
    foreach (string name in Enum.GetNames(typeof(enumType)))
    {
        Console.WriteLine(name);
    }
}

可以这样称呼

OutputEnumValues (typeof(HorizontalAlignment));
OutputEnumValues (typeof(VerticleAlignment ));

但我可能会无意中打电话,例如

OutputEnumValues (typeof(int));

这将在 Enum.GetNames() 处编译但在运行时失败

编写方法签名以在编译时捕获此类问题的任何方式 - 即仅接受 OutputEnumValues 中的枚举类型?

【问题讨论】:

    标签: c#


    【解决方案1】:

    每个枚举类型都只是一个整数(可以是 8 位、16 位、32 位或 64 位,有符号或无符号)。您可以将整数0 转换为任何枚举类型,它将成为静态类型为枚举的值。

    此外,您可以有一个Enum 类型的参数,以确保只传入枚举值,而不知道实际的枚举类型。

    因此,我的解决方案如下所示:

    public static void OutputEnumValues(Enum example)
    {
        foreach (string name in Enum.GetNames(example.GetType()))
        {
            Console.WriteLine(name);
        }
    }
    

    然后:

    OutputEnumValues((HorizontalAlignment) 0);
    OutputEnumValues((VerticalAlignment) 0);
    

    这适用于所有枚举类型,无论其底层整数类型如何。

    【讨论】:

    • 必须将键入的 0 传递给枚举有点“脏”,并且对于该方法的用户来说并不明显 - 但可能是最糟糕的选择,所以我要 +1。跨度>
    【解决方案2】:

    您真正想要的是一个可以限制为 Enum 类型的通用方法。但是,这在 C# 中是不可能的。

    Jon Skeet 在这个帖子中为这个问题提供了答案:Anyone know a good workaround for the lack of an enum generic constraint?

    对于你的方法,你真正想要的是

    public void OutputEnumValues<T>() where T : HorizontalAlignment
    {
        foreach (string name in Enum.GetNames(typeof(T)))
        {
            Console.WriteLine(name);
        }
    }
    

    但除非您使用 Jon 的建议,否则该约束将不起作用。

    【讨论】:

      【解决方案3】:

      我认为这在 C# 中是不可能的。

      您可以改为在 Enum 上使用扩展方法,但这需要您在实例而不是类型本身上调用它,这可能是不可取的。

      使用泛型的另一种解决方案是限制结构:

      public static void OutputValues<T>() where T : struct
      {
          if (!typeof(T).IsEnum)
              throw new NotSupportedException("Argument must be an enum.");
      
          // code here...
      }
      

      如果您尝试使用类调用它会产生编译时错误,但如果使用非 Enum 的结构调用它会产生运行时错误。

      【讨论】:

        【解决方案4】:

        我没有看到你所说的“问题”。

        你定义你的方法来获取一个 Type 对象。对于客户来说,任何类型似乎都足够了。但是,您随后假设该参数实际上是一个枚举。该错误在您的方法本身中。无论如何,该方法本身是人为设计的,因此不可能了解您实际尝试使用这样的代码解决的问题。

        再一次,你的方法的名字很明显地表明参数应该是一个枚举值。你可以认为这是一个合同,如果代码的客户违反了该合同,那么它就会在他们的脸上炸开。任何 API 都包含可以向其发送不良数据的方法。

        【讨论】:

        • 我认为他的问题很明确。是的,这个例子是人为的,但意图很明确。他不在乎传入的是什么类型的 Enum get,但他确实想确保它是某种 Enum 类型(所以 Enum.GetNames 不会失败)。这是具有枚举约束的通用方法的完美案例(但是,C# 目前不支持)
        • 所以...这是不受支持的语言功能的完美案例?有帮助。我要说的是,如果该方法被明确记录为采用枚举类型,那么该代码的客户端如果传入垃圾,就会得到他们应得的。谈论不存在的功能是浪费时间。
        • 我想我只是习惯了另一种编程风格。在我的世界中(系统/嵌入式)函数被记录为期望某些参数。如果您传递了不良数据,那么您将得到应得的。如果您可以将方法限制为仅采用枚举类型,那就太好了。既然你不能,我什至看不出讨论它的意义。我认为在运行时抛出异常没有问题。
        • “谈论不存在的功能是浪费时间”我不能不同意。如果没有这种讨论,语言将如何发展?创新的关键是讨论这些类型的事情。我了解您的环境中的差异,并且可以看到,鉴于清晰的文档,这样的事情似乎不是一个“问题”。然而,在许多(我什至会说大多数)情况下,文档是一种很少发现的奢侈品。您的代码应该尽可能精确,并引导代码的使用者进入“成功的坑”。拥有这种类型的通用约束有助于解决这个问题。
        猜你喜欢
        • 2013-04-16
        • 1970-01-01
        • 2019-10-27
        • 1970-01-01
        • 2014-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多