danatel
danatel

Reputation: 4982

Define enums within a method in C#?

I have mainly a C++ background and I am learning C#. So, I need some help with C# idioms and style.

I am trying to write, in C#, a small text-file parsing method in which I need a simple state variable with three states. In C++ I would declare an enum like this for the state variable:

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

...and then use it in my parsing loop like this:

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

In C# I realize that it is not possible to declare an enum inside a method. So, what I am supposed to do for sake of clean style? Declare this internal enum outside of the method? Use magic numbers 1,2,3? Create a separate class for this?

Please help me clear up my confusion.

Upvotes: 31

Views: 29199

Answers (6)

Gamba
Gamba

Reputation: 1

I know this was over a decade ago but I'd like to offer two solutions that I beleive look similar enough to what the OP was trying to do:

private void Option1()
{
    var State = new
    {
        Header = 0,
        Body = 1,
        Footer = 2,
    };

    var state = State.Body;

    // . . .

    if (state == State.Header)
    {
        state = State.Body;
    }
}

This option uses anonymous types to create a local enum-lookalike that groups named variables together. However, the main downsides are that it doesn't restrict the variable state to be only one of those options, like a proper enum would, and also you can't make it to be a constant so traditional switch statements won't work.

For traditional switch statements support, you can do something like this:

private void Option2()
{
    const int Header = 0, Body = 1, Footer = 2;

    int state = Body;

    // . . .

    switch (state)
    {
        case Header:

            // Do something

            break;

        case Body:

            // Do something

            break;

        case Footer:

            // Do something

            break;
    }
}

Upvotes: -1

samhaz
samhaz

Reputation: 1

I know this is old, so this is mainly for folks looking for ideas.

The closest I can think of to creating an 'enum' type, clean structure as required, within a method is to use a dictionary.

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

You can then do what you need in your condition...

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

Upvotes: 0

Minh Tran
Minh Tran

Reputation: 510

You can't declare an enum in method scope (recapping Willem van Rumpt's answer above) but instead you can declare an inner private class to do the state-tracking and reuse it in your class methods. The containing class or its clients need not know about that auxiliary class.

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
    }
}

In this case, Parser is your private inner class whose instances can track state -- it is not visible outside of Program. ParseFile is a method that utilizes Parser.

Output

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

Upvotes: 0

Alex Pinto
Alex Pinto

Reputation: 262

I would also favour the Enum approach. Plus, although that is not the case here, it has advantages over the CONSTS when you want to combine them as flags, since you have a method to easily test for that.

Upvotes: 0

Sergey K
Sergey K

Reputation: 4114

You can also use the constant variables but I prefer and I think is better code style to use Enums

 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();
        }

    }
}

Upvotes: 10

Willem van Rumpt
Willem van Rumpt

Reputation: 6570

The closest you can get is a private nested enum with in the class:

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

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

Upvotes: 37

Related Questions