Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List of const int instead of enum

I started working on a large c# code base and found the use of a static class with several const ints fields. This class is acting exactly like an enum would.

I would like to convert the class to an actual enum, but the powers that be said no. The main reason I would like to convert it is so that I could have the enum as the data type instead of int. This would help a lot with readability.

Is there any reason to not use enums and to use const ints instead? This is currently how the code is:

public int FieldA { get; set; }
public int FieldB { get; set; }

public static class Ids
{
    public const int ItemA = 1;
    public const int ItemB = 2;
    public const int ItemC = 3;
    public const int ItemD = 4;
    public const int ItemE = 5;
    public const int ItemF = 6;
}

However, I think it should be the following instead:

public Ids FieldA { get; set; }
public Ids FieldB { get; set; }
like image 924
Telavian Avatar asked Sep 08 '11 17:09

Telavian


2 Answers

I think many of the answers here ignore the implications of the semantics of enums.

  • You should consider using an enum when the entire set of all valid values (Ids) is known in advance, and is small enough to be declared in program code.

  • You should consider using an int when the set of known values is a subset of all the possible values - and the code only needs to be aware of this subset.

With regards to refactoring - when time and business contraints allow, it's a good idea to clean code up when the new design/implementation has clear benefit over the previous implementation and where the risk is well understood. In situations where the benefit is low or the risk is high (or both) it may be better to take the position of "do no harm" rather than "continuously improve". Only you are in a position to judge which case applies to your situation.

By the way, a case where neither enums or constant ints are necessarily a good idea is when the IDs represent the identifiers of records in an external store (like a database). It's often risky to hardcode such IDs in the program logic, as these values may actually be different in different environments (eg. Test, Dev, Production, etc). In such cases, loading the values at runtime may be a more appropriate solution.

like image 139
LBushkin Avatar answered Sep 23 '22 04:09

LBushkin


Your suggested solution looks elegant, but won't work as it stands, as you can't use instances of a static type. It's a bit trickier than that to emulate an enum.

There are a few possible reasons for choosing enum or const-int for the implementation, though I can't think of many strong ones for the actual example you've posted - on the face of it, it seems an ideal candidate for an enum.

A few ideas that spring to mind are:

Enums

  • They provide type-safety. You can't pass any old number where an enum value is required.
  • Values can be autogenerated
  • You can use reflection to easily convert between the 'values' and 'names'
  • You can easily enumerate the values in an enum in a loop, and then if you add new enum members the loop will automatically take them into account.
  • You can insert new enunm values without worrying about clashes occurring if you accidentally repeat a value.

const-ints

  • If you don't understand how to use enums (e.g. not knowing how to change the underlying data type of an enum, or how to set explicit values for enum values, or how to assign the same value to mulitple constants) you might mistakenly believe you're achieving something you can't use an enum for, by using a const.
  • If you're used to other languages you may just naturally approach the problem with consts, not realising that a better solution exists.
  • You can derive from classes to extend them, but annoyingly you can't derive a new enum from an existing one (which would be a really useful feature). Potentially you could therefore use a class (but not the one i your example!) to achieve an "extendable enum".
  • You can pass ints around easily. Using an enum may require you to be constantly casting (e.g.) data you receive from a database to and from the enumerated type. What you lose in type-safety you gain in convenience. At least until you pass the wrong number somewhere... :-)
  • If you use readonly rather than const, the values are stored in actual memory locations that are read when needed. This allows you to publish constants to another assembly that are read and used at runtime, rather than built into the other assembly, which means that you don't have to recompile the dependant assembly when you change any of the constants in your own assembly. This is an important consideration if you want to be able to patch a large application by just releasing updates for one or two assemblies.
  • I guess it is a way of making it clearer that the enum values must stay unchanged. With an enum another programmer will just drop in a new value without thinking, but a list of consts makes you stop and think "why is it like this? How do I add a new value safely?". But I'd achieve this by putting explicit values on the enums and adding a clear comment, rather than resorting to consts.

Why should you leave the implementation alone?

  • The code may well have been written by an idiot who has no good reason for what he did. But changing his code and showing him he's an idiot isn't a smart or helpful move.
  • There may be a good reason it's like that, and you will break something if you change it (e.g. it may need to be a class due to being accessed through reflection, being exposed through external interfaces, or to stop people easily serializing the values because they'll be broken by the obfuscation system you're using). No end of unnecessary bugs are introduced into systems by people who don't fully understand how something works, especially if they don't know how to test their changes to ensure they haven't broken anything.
  • The class may be autogenerated by an external tool, so it is the tool you need to fix, not the source code.
  • There may be a plan to do something more with that class in future (?!)
  • Even if it's safe to change, you will have to re-test everything that is affected by the change. If the code works as it stands, is the gain worth the pain? When working on legacy systems we will often see existing code of poor quality or just done a way we don't personally like, and we have to accept that it is not cost effective to "fix" it, no matter how much it niggles. Of course, you may also find yourself biting back an "I told you so!" when the const-based implementation fails due to lacking type-safety. But aside from type-safety, the implementation is ultimately no less efficient or effective than an enum.
like image 33
Jason Williams Avatar answered Sep 21 '22 04:09

Jason Williams