7

When Enum is used as below, say if we have

enum Designation
{
    Manager = 0,
    TeamLead = 1,
    Associate = 2
}

then write the below code

if (designation == Designation.TeamLead) //somecode

Now if we decide to change the enum element from "TeamLead" to "Lead" then we have to modify the above line of code as well i.e. designation == Designation.TeamLead to designation == Designation.Lead. So what is the best practice.

6
  • 14
    Not exactly relevant to what you're asking, but a best practice is to have 0 as None
    – superM
    May 13, 2013 at 14:03
  • 5
    Best practice with regard to what? What is the question? What are you concerned about? May 13, 2013 at 14:14
  • 6
    This is why you use enum so you CAN rename them. VS renaming tools work just fine on enum.
    – Reactgular
    May 13, 2013 at 14:47
  • 2
    Why do you explicitly assign the values 0, 1, and 2 (which are the default values anyway)? Are you going to write code that depends on Associate having the value 2? What would you lose by writing enum Designation { Manager, TeamLead, Associate }? May 13, 2013 at 17:18
  • 3
    You may not be, but this question makes me feel like you're using the name of the enum as the displayed value for some property. IE, designation.ToString() somewhere in your UI. This is absolutely bad practice.
    – dlras2
    May 13, 2013 at 20:21

6 Answers 6

24

The most basic answer to your question is this: Most C# IDEs I know of have a Refactoring option that easily lets you rename variables and references, such as enum types. If you highlight TeamLead, anywhere it's used, right-click it and look for a Rename option, you should be able to change references in all code files of your project. If you reference it as a string at some point, it may be good to do a full text search and handle individual cases.

However, my full answer, which I can only hope you care about, is that this is the wrong way of going about things in an object-oriented language. You should especially take note of times when you're seperating large blocks of logic by an if-else/switch, and even using part of one block in another, as a time when object-oriented design would help you. Here's how I'd do it, in incomplete pseudo-code:

abstract class ProjectMember {
    public abstract void reassignTask(Task t);
}

class Manager : ProjectMember {
    public void reassignTask(Task t) {
        // TODO: manager case
    }
}

class TeamLead : ProjectMember {
    public void reassignTask(Task t) {
        // TODO: TeamLead case
    }
}

class Associate : ProjectMember {
    public void reassignTask(Task t) {
        // TODO: associate case
    }
}


// this is the function where you'd be getting rid of a switch statement, by way of the above code.
void reassignMemberTask(ProjectMember mem, Task t) {
    mem.reassignTask(t);
}
7
  • This is way overkill for this scenario. It might also be entirely infeasible if there's also an enum representing what team the user is on, and the logic is based on the combination thereof. It certainly could be the right answer (and the OP accepted it), but it isn't always.
    – Bobson
    May 13, 2013 at 15:19
  • 1
    Well, then you'd have a Team class, and an instance of that in your ProjectMember class. Then, you can have code specific to that Team. I was also going under the assumption that this was hardly the only enum-selecting piece of code they were going to have. It's especially useful if you have, for instance, a TeamLeadAssistant class that's just a tiny functional modification of TeamLead. If the project uses these often, then it becomes less and less of an overkill.
    – Katana314
    May 13, 2013 at 15:30
  • 1
    switch statements are procedural overkill more often than not. Object dispatch exists exactly for this reason, but there needs to be sufficient amount of code in the different switch cases (or sufficient proof they are a part of the system that will surely grow and change with time) to prove necessity for an object hierarchy. This usually is the right way to go though. May 13, 2013 at 15:39
  • 2
    @Katana314 Nicely done. I agree with your approach. Too often I have seen methods such as reassignTask that contain massive switch statements or if/else that evaluate every permutation of an enum. May 13, 2013 at 15:42
  • 1
    By the time you've got a number of switch statements it's too risky to change the switch statements (there is something to be said for working code, testable or not). If the application is not a proof of concept (POF) or not a throw away application us an object hierarchy. May 13, 2013 at 15:54
7

Renaming an element of an enum is not a problem: Visual Studio does that for you, while ensuring that every reference to it will be renamed as well.

On the other hand, other issues may arise when "reusing" the elements in such way:

  1. Business behavior

    Imagine that TeamLead is a team lead, while Lead is a lead developer in a team. Imagine the following piece of code:

    if (role != Designation.TeamLead)
    {
        // The user cannot fire a member of a team: only a team lead can do it.
        this.DenyFiringTeamMember();
    }
    

    If you rename the role, you will miss the business rules, i.e. the fact that only a team lead can fire a team member. Now, lead developer can fire other developers, while only team lead is expected to be able to do it.

  2. Dependencies

    Unless you're Google, you may have dependencies in external projects. Visual Studio won't be able to find those, so the problem will arise the next time you open a solution which is referencing the old TeamLead.

  3. ToString

    Sometimes, and this is an extremely bad practice, the item from the enum is converted to string, and then used in a comparison, or stored in database, etc. Example:

    if (role.ToString() == "TeamLead")
    {
        // I never understood how to compare variables, and I don't care.
    }
    

    Renaming the element will break those pieces of code. Maybe it's better: you'll be able to find them and rewrite them correctly.

3
  • Point 3: to do simple string comparisons, the issue can be resolved writing Designation.TeamLead.ToString() instead of "TeamLead", so when you refactor, the new value is updated automatically and the comparison works as before. The issue remains if you store the string in a database (a file, a sql database, ecc), but maybe you better store the int value beyond the enum, not the string representation... Do you agree? May 31, 2016 at 10:17
  • @MK87: I agree completely with your both points. Storing enum values in a database is indeed problematic; if you use integers, this could lead to another problem of adding values in the middle of an enum or removing a value from the middle (shifting the other values). I think the only sane way is to have a converter which binds the enum values (identified as Designation.TeamLead, and not a string or an int) to the corresponding meaningful values from the database—varchars or maybe numbers specified as constants in code. May 31, 2016 at 11:51
  • Yep, a bridge/converter/facade/mediator between the enum and the db seems the most solid solution to me too. May 31, 2016 at 16:19
1

Just use a refactoring tool. You cannot circumvent the fact that if you rename something you have to rename it everywhere but a refactoring tool will make that easy.

3
  • Why the down vote?
    – Sarien
    May 13, 2013 at 14:25
  • 1
    +1 I don't know why you got downvoted. It's a reasonable answer. May 13, 2013 at 15:46
  • @ChuckConway well - I have not downvoted it, but it doesn't really answer the question. The question is poorly phrased anyhow, but it's clearly asking about best practices (the author just failed to specify what he is concerned about). He's asking about what he should do, not how. May 14, 2013 at 11:34
1

Most refactoring tools can easily help with this. It allows mass renaming based on language semantics, not only text-replace.

But if you use complex enums for business logic, I would start thinking if you shouldn't be using proper OOP.

1
  • +1 I don't know why you got downvoted. It's a reasonable answer. May 13, 2013 at 15:48
1

I will answer, not because I think the other answers are bad, but because I think there is another thing to be said in this case.

We have two questions in one:

  1. About best practice for you Enum
  2. About refactoring an Enum

1)Is this a Best Practice with Enum in C#?

Well, in your case, since you Enum seems to be kind of hierarchic, I would define them as flags, and benefit from that when using and comparing the values.

[Flags]
enum Designation
{
    None = 0x0,
    TeamLead = 0x1,
    Manager = 0x2,
    Associate = 0x4
}

Then you could use a code like this:

    string CheckAboveManager(Designation designation)
    {
        if (designation >= Designation.Manager)
            return "It's a manager or higher";
        return "Is lower than manager";
    }

The other option of using a object-oriented structure will work only if there is specific behavior or structure you want to separate concerns with. If it is a case of just defining a property (that why there are enums!), them I see no need to create inheritance, but if it is the case, use the accepted answer.

2) Now if we decide to change the enum element from "TeamLead" to "Lead" then we have to modify the above line of code as well i.e. designation == Designation.TeamLead to designation == Designation.Lead

Well, it was already well explained that refactoring is not an issue if you are using VS IDE, you can even use other tools like DevExpress CodeRush! or ReSharper to get an even better (and very safe) result from refactoring.

1
  • When adding the Flags attribute to a enum it is best practice to make the enum name plural, like Designations in this case. Defining a default value is a good idea because comparing your enum with default(value) should result in the most cases to a invalid/unknown value.
    – seveves
    Feb 16, 2016 at 7:49
0

If you rename the enum member in a DLL, the caller code needs to be modified and recompiled.

This may break binary compatibility. You need to ensure the caller code is possible to be modified.

1
  • Only relevant if the enum is public.
    – Marcel
    May 14, 2013 at 6:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.