4

Picture the scene.

public enum SaveStates
{
    Saved,               //Represents a successful save.
    SavedWithChanges,    //Represents a successful save, where records were modified
    SavedWithoutChanges  //Represents a successful save, but no records were modified
}

In this scenario, the enumeration can be considered Saved if it's SavedWithChanges or SavedWithoutChanges.

So if I were to have a variable like this:

SaveStates lastState = SaveStates.SavedWithoutChanges;

I'd ideally like to do something like this:

if (lastState == SaveStates.Saved)
{
    //The state is saved, do something awesome.
}

I can of course do this:

if (lastState == SaveStates.SavedWithChanges || lastState == SaveStates.SavedWithoutChanges)
{
    ...

However this is a bit tedious and I can't assume that another developer is going to understand how to correctly use the enumeration.

Each enumeration is required as there may be an instance where we might want to do something specific in the event of a save where there has been no changes for example.

I'm open to alternative design ideas.

2
  • 1
    I don't think that another developer won't understand that. Imo this is clearer than using flags attribute . Commented Oct 15, 2015 at 11:30
  • Shouldn't you have an unsaved value for you enum? Otherwise why check it to see if it is saved, you'd just use Enum.IsDefined. Commented Oct 15, 2015 at 11:50

6 Answers 6

5

If what worries you is code readability, you can use a little extension method like this:

public static class SaveStatesExtension
{
    public static bool IsSavedState(this SaveStates state) {
        return state == SaveStates.SavedWithChanges || 
               state == SaveStates.SavedWithoutChanges;
    }
}

Then your usage example becomes:

if (lastState.IsSavedState())
{
    //The state is saved, do something awesome.
}

Of course the Saved member in the enum is no longer needed in this case.

Sign up to request clarification or add additional context in comments.

Comments

3

If you're going to do it with a Flags enum, you should make it self-documenting

[Flags]
public enum SaveStates
{
    Saved = 1,
    WithChanges = 2,
    SavedWithoutChanges = Saved, // a bit pointless! Its the same as Saved
    SavedWithChanges = Saved | WithChanges  // has value "3"
}

And then, as per other answers

if ((lastState & SaveStates.Saved) == SaveStates.Saved)
{

}

5 Comments

Is it me or are you doing these flags completely wrong. When using flags you should use all components. And do Saved as Saved = With | Without
Upvoting this answer. For me, it's more intuitive that whether something was "Saved" and "Was Changed" are two different things. Putting them into one enum causes part of the confusion. I would probably take it a step further and have a property for both Save state and Change state. Why do I think this? What will you do when you save something with changes, then make a change and save it again? You have to evaluate whether prior changes have been made when determining the new enum to select. Everything else can be wrapped up into extension methods to set/get these values as needed.
@kevintjuh93 - it's you ;)
@Jamiec but seriously... Saved is both with and without changes. So it should be the other way around.
@kevintjuh93 whether this is a good scheme is up to the OP, I agree it may not be the best way to represent the saved state of something. This answer was an attempt to show that, while its possible to do with a Flags enum (as per the answers that came before mine) there is a way to do it the same way, but to add some level of self-documentation to the code.
3

You can achieve this as follows, going by the example of the link I've posted under the question but using non-exclusive flag values. Note that both SavedWithChanges and SavedWithoutChanges contain the bit 1, assigned to Saved.

[Flags]
public enum SaveStates
{
    Saved = 1,
    SavedWithChanges = 3,
    SavedWithoutChanges = 5
}

if ((lastState & SaveStates.Saved) == SaveStates.Saved)
{

}

However, this can be rather unintuitive to other developers - usually flag enums are not used this way. So explicitly stating all conditions with all enum values might be much more readable. Very good idea posted by Konamiman:

public static bool IsSaved(SaveStates state)
{
    return state == SaveStates.SavedWithChanges
        || state == SaveStates.SavedWithoutChanges;
}

combines best of two worlds: principle of least astonishment satisfied while being concise and readable.

Comments

1

What about changing your enumeration?

public enum SaveStates
{
    NotSaved,               //Represents "not saved" state
    SavedWithChanges,    //Represents a successful save, where records were modified
    SavedWithoutChanges  //Represents a successful save, but no records were modified
}

In this case you can use negation for the purpose you're speaking of:

if (lastState != SaveStates.NotSaved)
{
    //The state is saved, do something awesome.
}

Also, it gives you an enumeration value which can be used as the "default" one which is considered a good, "clean code" practice.

Comments

0

I would prefer this:

SaveStates[] savedWithOrWithoutChanges = { SaveStates.SavedWithChanges, SaveStates.SavedWithoutChanges };
if (savedWithOrWithoutChanges.Contains(lastStat))
{
    ...
}

This is very intuitive, every developer will understand it.

Comments

0

Instead of one enum to represent two things why not just use two bool values. One to indicate if it is saved and the other to indicate if it is "with changes". Then you'd just ignore the second if the first is false.

private bool saved;

private bool withChanges;

public void SomeMethod()
{
    if (saved)
    {
        Console.WriteLine("Saved");

        if (withChanges)
        {
            Console.WriteLine("With Changes");
        }
        else
        {
            Console.WriteLine("Without Changes");
        }
    }
    else
    {
        Console.WriteLine("Not saved");
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.