3

I have a standard C# enum representing bank accounts:

public enum Accounts
{
    BankOfAmerica = 123654,
    BankOfIndia = 765091
}

This enum is used in many places in my code. Some objects use it for using the account number as a string ("123654"), as an integer (123654) or the name of the account as a string ("BankOfAmerica").

The accounts number change and they contain also digits, therefore I can't simply change the enum...

Can someone point a way to make this change as painless as possible, with the minimum number of changes in the code?

I thought of replacing the enum with a singleton class containing the account names and values, but then many code changes were necessary to replace the usage of the old enum with the new class.

5
  • 2
    "The accounts number changed and they contain also digits" - You mean the account number is not an int anymore? Commented Dec 12, 2011 at 21:59
  • I would not use an enum to hold magic-number constants like this in C#. Commented Dec 12, 2011 at 22:00
  • Not sure what do you mean, maybe this - int accountAsInt = (int) Accounts.BankOfAmerica; string accountNumberAsString = accountAsInt.ToString(); string accountNameAsString = Accounts.BankOfAmerica.ToString(); Commented Dec 12, 2011 at 22:03
  • Some more details would help. Are you holding a fixed number of accounts? A variable list of accounts? For one user? For many users? Commented Dec 12, 2011 at 22:04
  • You probably wanted to say that the account number could also contain letters, I assume. Not digits. Commented Dec 13, 2011 at 14:25

6 Answers 6

8

The accounts number changed and they contain also digits...

You're using the wrong tool for the job then. The values of an enumerated type are meant to be defined at compile time. If the account numbers change then you should be using a more advanced type (i.e., a class) which will allow for mutation (if needed) and also more advanced formatting for the UI layer.

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

Comments

4

Ed S. is correct; an enum is the wrong tool for the job. To elaborate on his answer:

Enum values are constants and constants are required to be logically constant for all time, past, present and future. If an enum value can possibly change over time without its meaning changing then it should not be an enum or const in the first place.

Similarly, if the set of things in the enum can change over time, even if their values stay the same, then an enum is probably a bad idea. You do not want to be in this situation:

enum Banks 
{
    BankOfFoo,
    BankOfBar,
    BankOfBlah,
    BankOfABC
}

and then next version, Bank Of Foo has bought Bank of Bar, Bank of Blah has gone out of business and Bank of ABC has changed their name to Bank of DEF, and a brand new Bank Of XYZ has been formed.

Enums are the wrong mechanism for representing stuff that changes over time. You should not be using an enum for this, and you should not be using a const string either.

2 Comments

On a completely unrelated side note; I just implemented a version of your "Shadow Caster" in the RPG Maker engine. Neat, thanks for that.
@EdS.: You're welcome! Note of course that this is not my algorithm; the articles on RogueBasin that I linked to detail the history of the development of the algorithm. Though as you'll see over the next few weeks, I've made a number of subtle changes to it that I hope improve it slightly.
3
var accounts = new Dictionary<string,string>();
accounts.Add("Bank of America", "ABC12345");
accounts.Add("Bank of India", "122-6X-666");

string number = accounts["Bank of America"];

Or, if you prefer to stick to an enum:

public enum Accounts {
    BankOfAmerica,
    BankOfIndia
}

var accounts = new Dictionary<Accounts,string>();
accounts.Add(Accounts.BankOfAmerica, "ABC12345");
accounts.Add(Accounts.BankOfIndia, "122-6X-666");

string number = accounts[Accounts.BankOfAmerica];

4 Comments

This is the right answer, although you may want to store the actual account number in either a settings file or a data store somewhere.
Yes, you, or even better, your users should be able to add accounts, without having to change your code.
The dictionary is great; sticking to an enum is probably a bad idea. If the set of things can change in the future then an enum is a bad idea.
The enums are just a concession to user1094626 and to his wish of having a kind of enum of strings. I agree that it is a bad idea.
1

You would be better off using a class for BankAccount, like so:

public class BankAccount
{
    public string Name { get; set; }
    public int Number { get; set;}

    public BankAccount(string name, int number)
    {
        Name = name;
        Number = number;
    }
}

And then holding the actual accounts in a collection, like a List:

public List<BankAccount> BankAccounts = new List<BankAccount>();

You can then easily search the bank account by number or by name, or pretty much by any property by using a loop or LINQ:

public BankAccount GetAccountByName(string name)
{
    return BankAccounts.FirstOrDefault(a => a.Name == name);
}

And when you've found the BankAccount object you want to change, it's just a matter of changing the property:

var account = GetAccountByName("BankOfAmerica");

account.Number = 12345678;

Or by creating a method that does that for you. Enums aren't the way to go with this; they're a collection of constants which have to be defined at compile time, and aren't meant to be changed. Even if it takes you a lot of time to implement a change like this, it's worth it in the long run and will only make things easier from there on.

5 Comments

Yes, or you could use a dictionary, using the bank name as key. The List has the advantage, that it can be used as data source for a combo box for example. The dictionary finds accounts faster, especially if the number of accounts grows in the future.
@OlivierJacot-Descombes I've never really been a fan of dictionaries. Do you mean the ease of access when you mentioned that it finds accounts faster? As far as I know, a Dictionary uses a list internally as well.
@OlivierJacot-Descombes: Your solution is clumsy. Don't use enum unless necessary. Aevitas' solution is just perfect.
@aevitas: Dictionaries are organized in a fully different manner than lists, even if both use an array internally. The Dictionary uses the array as a so-called hash table. The time required to find an item in a dictionary does NOT depend on the number of stored items! The time is (more or less) constant. This is denoted as O(1). Whereas the time to find an item in a list by scanning the list, is proportional to the length of the list, O(n). If the list is sorted, then a binary search can be applied, which performs with O(log(n)).
@dzendras: I show two solutions. The first, without enums, is the one I prefer by far, because accounts could be retrieved from some flexible data source. The second, with enums, is a concession to user1094626 and to his wish of having a kind of enum of strings.
0

Why don't you use Attributes?

class AccountAttribute : Attribute 
{
    public string MyValue { get; set; }
    // add any other stuff...
}

public enum Accounts
{
    [Account(MyValue = "A")]
    BankOfAmerica = 123654,

    [Account(MyValue = "B")]
    BankOfIndia = 765091
}

After that, you just use stadard reflexion to get your custom attributes on your fields.

3 Comments

+1 For answering the OP's question directly. This is definitely the wrong way to do it, though.
Brian is right; this is a bad idea. Attributes should be used to indicate facts about the mechanism of the class; they should not be used to convey information about the business domain of the code. For example, you might have a class OilLamp that you mark as "Obsolete" with the ObsoleteAttribute. That is not saying that oil lamps are no longer saleable in the market; that is saying that the class is no longer the right class to use and has been replaced with a different class.
I totally agree with both of you. I just gave an alternative. But Brian, I don't totally agree with your comment. Attributes are there to attach compile-time constant to properties, fields, class or methods. For instance, if you want to attach extra information to an enum field you might want to have that extra information right with the enum definition. Having 2 different places (using a dictionary) in the code is hard for the maintenance. But for what the OP wants, it's definitely not a good example.
0

I don't think any of these answers properly address this question. What is really needed here is a database to store this data which can change over time. Trying to store changing data in code is generally a bad idea, because it will require that you recompile every time the data changes.

A database table with columns for the AccountId, AccountName (and possibly other data that needs to be stored) is definitely the most robust solution. If this is just a quick and dirty app it doesn't even need to be a full fledged database, something like SQLite or SQL Server Express would work.

You can then access this table through code with ADO .NET or an Object-Relational-Mapper of your choice.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.