【问题标题】:Define enums within a method in C#?在 C# 的方法中定义枚举?
【发布时间】:2011-04-09 08:45:42
【问题描述】:

我主要有 C++ 背景,我正在学习 C#。所以,我需要一些 C# 习语和风格方面的帮助。

我正在尝试用 C# 编写一个小型文本文件解析方法,其中我需要一个具有三种状态的简单状态变量。在 C++ 中,我会为状态变量声明一个像这样的enum

enum { stHeader, stBody, stFooter} state = stBody;

...然后像这样在我的解析循环中使用它:

if (state == stHeader && input == ".endheader")
{
  state = stBody;
}

在 C# 中,我意识到不可能在方法内声明 enum。那么,为了干净的风格,我应该怎么做?在方法之外声明这个内部enum?使用幻数 1,2,3?为此创建一个单独的类?

请帮我解惑。

【问题讨论】:

  • 也许我遗漏了一些东西,但如果枚举仅用于单一方法,那么它的意义何在?
  • @Dogget - 为状态提供可读的名称。否则我将不得不写 if (state == 2 && input == ".endheader") state = 1;
  • 状态的自注释等。在 C 语言中很常见,即在给出的示例中 - 将状态作为比 int 更有意义的东西。我不得不说,它在 C# 中出现的频率较低 - 主要是因为您倾向于将方法分解为更小的组件、对象等,而不是更面向命令的 C。或者 C++,当它与 C 类似时使用。

标签: c# enums coding-style


【解决方案1】:

您可以获得的最接近的是类中的私有嵌套枚举:

public class TheClass
{
    private enum TheEnum 
    {
       stHeader, 
       stBody, 
       stFooter
    }

    // ...the rest of the methods properties etc... 
}

【讨论】:

  • 这是变态的,因为状态在方法之外没有任何意义。这就像在方法之外声明循环变量。此外,你需要给它一个名字!
  • 欢迎来到保守的企业语言世界。情况可能更糟,可能是 java :D
  • @danatel:我不制定规则 :)
  • @willem van Rumpt。感谢你的回答。对我来说,声明三个独立的 consts (const int stHeader=0; ) 看起来不那么邪恶。
  • @danatel:我自己会去枚举,但本质上,它归结为同一件事:)
【解决方案2】:

您也可以使用常量变量,但我更喜欢并且我认为使用更好的代码样式 枚举

 public class Class1
{
    private enum TheEnum
    {
        stHeader,
        stBody,
        stFooter
    }
    public void SomeMethodEnum()
    {
        TheEnum state = TheEnum.stBody;
        switch (state)
        {
            case TheEnum.stHeader:
                //do something
                break;
            case TheEnum.stBody:
                break;
            case TheEnum.stFooter:
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }


    public void SomeMethodConst()
    {
        int state = 1;
        const int Header = 1;
        const int Body = 2;
        const int Footer = 3;

        switch (state)
        {
            case Header:
                break;
            case Body:
                break;
            case Footer:
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }

    }
}

【讨论】:

    【解决方案3】:

    我也赞成 Enum 方法。另外,虽然这里不是这种情况,但当您想将它们组合为标志时,它比 CONSTS 具有优势,因为您有一种方法可以轻松测试它。

    【讨论】:

      【解决方案4】:

      您不能在方法范围内声明enum(重述上面的Willem van Rumpt's answer),而是可以声明一个内部私有类来进行状态跟踪并在您的类方法中重用它。包含类或其客户不需要知道该辅助类。

      class Program
      {
          private class Parser
          {
              public string pname = "ParserPam"; 
              public enum pstate { rewind=-1, stdHeader, stBody, stFooter }
      
              public pstate state = pstate.stdHeader; 
      
              //Implement state transition logic as methods
              public void tick() => this.state = pstate.stBody;
              public void tock() => this.state = pstate.stFooter;
              public void rewind() => this.state = this.state - 1;
      
              public override string ToString()
              {
                  return $"{this.pname} state: {this.state}";
              }
          }
      
          static void ParseFile(string filename)
          { 
              Parser fp = new Parser(); //This object tracks your method's state
      
              Console.WriteLine(fp); // "ParserPam state: stdHeader"
              if (fp.state == Parser.pstate.stdHeader)
              { 
                  fp.tick(); // Transition
                  // Do stuff
              }
      
              // Do more stuff
              Console.WriteLine(fp); // "ParserPam state: stBody"
              fp.tock();
              Console.WriteLine(fp); // "ParserPam state: stFooter"
              fp.rewind();
              Console.WriteLine(fp); // "ParserPam state: stBody"
          }
      
          static void Main(string[] args)
          {
              ParseFile( @"C:\Example" ); // Client call
          }
      }
      

      在这种情况下,Parser 是您的私有内部类,其实例可以跟踪状态——它在Program 之外不可见。 ParseFile 是一种利用Parser 的方法。

      输出

      ParserPam state: stdHeader
      ParserPam state: stdBody
      ParserPam state: stFooter
      ParserPam state: stBody
      

      【讨论】:

        【解决方案5】:

        我知道这是旧的,所以这主要是为了寻找想法的人。

        我能想到的最接近在方法中创建“枚举”类型、根据需要清洁结构的方法是使用字典。

        var stateOpt = new Dictionary<string, byte>() { { "stHeader", 0 }, { "stBody", 1 }, { "stFooter", 2 } };
        var state = stateOpt["stBody"];
        

        然后你就可以在你的情况下做你需要的事情......

        if (state == stateOpt["stHeader"] && input == ".endheader")
        {
          state = stateOpt["stBody"];
        }
        

        【讨论】:

        • OP 并没有要求最高效或最具成本效益,他们要求的是“为了干净的风格”,我认为这很好,很干净。
        猜你喜欢
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-24
        • 1970-01-01
        • 2012-05-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多