在枚举中使用字符串

3

我有一个表示银行账户的标准C#枚举:

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

这个枚举在我的代码中有许多用途。有些对象使用它将账号编号用作字符串("123654"),数字(123654)或账号名称作为字符串("BankOfAmerica")。

账户号码会改变,而且它们还包含数字,因此我不能简单地更改枚举...

有人能指出一种尽可能无痛地进行此更改的方法,并且最小化代码更改的数量吗?

我考虑过用单例类替换枚举,其中包含帐户名称和值,但是这样需要进行许多代码更改,以替换旧枚举的使用。


2
账户号码已更改,现在它们也包含数字。您的意思是账户号码不再是整数了吗? - Daniel Moses
我不会在C#中使用“枚举”来保存类似于魔术数字常量的内容。 - James Michael Hare
不确定你的意思,也许是这样的 - int accountAsInt = (int) Accounts.BankOfAmerica; string accountNumberAsString = accountAsInt.ToString(); string accountNameAsString = Accounts.BankOfAmerica.ToString(); - Maxim
一些更多的细节会有所帮助。您是否持有固定数量的账户?还是一个可变的账户列表?是为一个用户还是多个用户? - James Michael Hare
你可能想说帐户号码也可以包含字母,我猜测。不是数字。 - Olivier Jacot-Descombes
6个回答

8

账号编号已更改,现在包含数字...

你使用的工具不适合这个任务。枚举类型的值应该在编译时定义。如果账号编号发生变化,你应该使用更高级的类型(即类),它将允许突变(如果需要),并且还可以为 UI 层提供更高级的格式。


4
Ed S.是正确的;枚举类型并不适合这个工作。细说一下:
枚举值是常量,而常量需要在时间上“永久、不变”,无论过去、现在还是未来都如此。如果一个枚举值可能会随时间而改变,而其“含义”不变,则它本应该不是枚举或常量。
同样地,如果“枚举类型中的事物集合”会随时间而改变,即使它们的值保持不变,那么枚举类型也可能不是个好主意。你不想陷入这种境地:
enum Banks 
{
    BankOfFoo,
    BankOfBar,
    BankOfBlah,
    BankOfABC
}

在下一个版本中,Foo银行收购了Bar银行,Blah银行已经倒闭,ABC银行更名为DEF银行,并且成立了全新的XYZ银行。
枚举不是代表随时间变化的事物的正确机制。您不应该使用枚举来做这件事,也不应该使用const字符串。

完全不相关的一面笔记:我刚在RPG Maker引擎中实现了你的“Shadow Caster”的一个版本。很棒,谢谢你。 - Ed S.
@EdS.: 不用客气!当然,这不是我的算法;我提供的RogueBasin上的文章详细介绍了算法的开发历程。但是,正如你在接下来的几周里会看到的,我对它进行了一些微小的改动,希望能稍微改进它。 - Eric Lippert

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"];

或者,如果你更喜欢使用枚举:

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];

1
这是正确的答案,尽管您可能希望将实际账号存储在设置文件或数据存储中。 - Andrew Hanlon
是的,您甚至更好的用户应该能够添加帐户,而无需更改您的代码。 - Olivier Jacot-Descombes
字典很棒;坚持使用枚举可能不是一个好主意。如果事物的集合在未来可能会发生变化,那么枚举就不是一个好主意。 - Eric Lippert
枚举只是为了迎合用户1094626的愿望而存在,他希望有一种字符串枚举的方式。我同意这是个不好的想法。 - Olivier Jacot-Descombes

1
你最好使用一个类来表示BankAccount,如下所示:
public class BankAccount
{
    public string Name { get; set; }
    public int Number { get; set;}

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

然后将实际账户保存在一个集合中,例如 List:

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

然后,您可以通过循环或LINQ轻松按编号或名称搜索银行账户,或者几乎按任何属性搜索:

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

当您找到要更改的BankAccount对象时,只需更改属性即可:

var account = GetAccountByName("BankOfAmerica");

account.Number = 12345678;

或者通过创建一个为您执行此操作的方法。枚举不是解决这个问题的方法;它们是在编译时定义的常量集合,不应该被更改。即使实现这样的更改需要花费很多时间,但从长远来看,它是值得的,并且只会使事情变得更容易。

是的,或者你可以使用字典,以银行名称作为键。列表的优点是它可以用作例如组合框的数据源。如果账户数量在未来增长,那么字典会更快地找到账户。 - Olivier Jacot-Descombes
@OlivierJacot-Descombes 我从来不是字典的粉丝。你提到它更快地查找账户时,是指易于访问吗?据我所知,字典内部也使用列表。 - aevitas
@OlivierJacot-Descombes:你的解决方案很笨拙。除非必要,不要使用枚举。Aevitas的解决方案非常完美。 - dzendras
@aevitas:字典与列表的组织方式完全不同,即使两者都在内部使用数组。字典将该数组作为所谓的哈希表使用。在字典中查找项目所需的时间并不取决于存储项目的数量!时间是(多或少)恒定的,这表示为O(1)。而在列表中查找项目所需的时间通过扫描列表与列表长度成比例,是O(n)。如果列表已排序,则可以应用二分查找,其执行效率为O(log(n))。 - Olivier Jacot-Descombes
@dzendras:我提供了两个解决方案。第一个方案没有枚举,是我更加喜欢的一种,因为账户可以从某些灵活的数据源中检索到。第二个方案使用枚举,是对user1094626的让步,满足他想要一种字符串枚举的愿望。 - Olivier Jacot-Descombes

0

我认为这些答案都没有恰当地回答这个问题。真正需要的是一个数据库来存储这些数据,因为它们可能会随着时间的推移而改变。试图在代码中存储可变数据通常是不明智的,因为每次数据更改都需要重新编译。

一个包含账户ID账户名称(以及可能需要存储的其他数据)列的数据库表肯定是最强大的解决方案。如果这只是一个快速而简单的应用程序,甚至不需要成为一个完整的数据库,像SQLite或SQL Server Express之类的东西就可以工作。

然后,您可以通过ADO .NET或您选择的对象关系映射器访问此表。


0

为什么不使用属性?

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
}

之后,您只需使用标准反射即可获取字段上的自定义属性。


直接回答楼主的问题+1。不过这绝对不是正确的方法。 - Brian
1
Brian是正确的;这是一个糟糕的想法。属性应该用于指示类的机制相关的事实;它们不应该用于传达代码业务领域的信息。例如,您可能有一个标记为“Obsolete”的OilLamp类。这并不意味着油灯在市场上已经不再销售;这意味着该类不再是正确的类,并且已被替换为另一个类。 - Eric Lippert
我完全同意你们两个的观点。我只是提供了一种替代方案。但是,Brian,我不完全同意你的评论。属性存在的目的是将编译时常量附加到属性、字段、类或方法上。例如,如果您想将额外的信息附加到枚举字段上,您可能希望将该额外信息与枚举定义放在一起。在代码中使用2个不同的位置(使用字典)很难维护。但对于OP想要的内容来说,这绝对不是一个好的例子。 - Sauleil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接