What is a good substitute for a big switch-case?
我有一个叫国家的东西。在程序的某个时刻,我想设置每个对象的场功率。
每个国家的权力是固定的,我在一张纸上有196个国家的数据。例如,我的代码应该检查这个国家的名称是否是美国(如果是,则将其功率设置为100),依此类推。
我知道我可以用一个开关盒来做,但是什么是最好、最好和最有效的方法呢?
- 使用Dictionary作为查找表。
- 我认为switch语句不会那么大。switch (country) { case"USA": return 100; default: return 0; }
- 福波:不好意思挑剔,但你误解了国家和州。国家是地理单位,没有权力…更重要的是,请注意,由于您有许多国家,因此子类化(即由其他类别继承国家)不是一个选项。但是,如果您只有几个可能的值,则可以有class country::weak、class country::medium、class country::strong,每个值都有自己的功率常量。
- 感谢您的评论:)在我的代码中,他们被称为玩家,我在这里写了国家,这样阅读的人会有更好的感觉!
- 你可以试一下。
您可以将国家电源对存储到Dictionary中,然后使用索引器获取特定国家的分数:
1 2 3
| var points = new Dictionary <string, int>();
// populate the dictionary...
var usa = points ["USA"]; |
编辑:正如注释中建议的那样,您应该将信息存储在外部文件中,例如XML是一个不错的选择。这样就不必修改代码来添加或删除国家。您只需要将它们存储到XML文件中,在需要的时候对其进行编辑,然后在程序启动时对其进行解析,并将值加载到Dictionary中。您可以使用LINQ to XML来实现这一点。如果您还没有使用它,文档中就有了一些好的示例来启动。
- 我建议将数据存储在文件或数据库中,即不存储在代码中!196个数据集的数量绝对不适合硬编码。
- 为了增加@comfreek所说的内容,json将非常适合,并且是一种很好的可移植格式,具有很容易解析为字典的现有方法。
- 谢谢你的编辑,真的很有帮助
- 读取文件的一个非常简单的方法是:var dict = System.IO.File.ReadLines(@"C:\path\file.extension").Select(line => line.Split(',')).ToDictionary(arr => arr[0], arr => int.Parse(arr[1]));,它假定文件是逗号分隔的文本格式(如.csv文件),没有空行。当然,在很多情况下都会出现例外情况。如果需要更健壮,当然可以选择一个XML方案,如问题的最后一节中所建议的那样。
- 向崇尚外部文件的人:吻,雅格尼!OP告诉我们"每个国家的力量是固定的"。硬编码是一种很好的解决方案,如果需要,可以很容易地进行改进。当然,需求可能会改变,但可能不会。看看管理外部资源增加的复杂性:文件丢失、编码错误、损坏;现在处理异常、记录错误、通知用户。此外,一个简单的开关就足够了:编译器无论如何都会生成一个字典(见我的答案)。
- @coredump和一个进一步的评论补充说,"在我的代码中,他们被称为玩家,我在这里写的国家,这样阅读的人会得到更好的感觉",所以不能保证它将被固定到196-根据大多数统计,有209个国家,或193个联合国成员国,2个观察员和11个"其他国家"。
- @核心倾倒区-国家数量是固定的,不会有新的税收。而且,他从未说过每个国家的权力是固定的。游戏有扩展包…
虽然塞尔曼的答案是正确的和好的,但它不回答如何实际填充字典。这里是:
1 2 3 4
| var map = new Dictionary <string, int> {
{"USA", 100},
{"Germany", 110}
}; |
但是,您也可以按如下方式添加:
1 2
| map.Add("USA", 100);
map.Add("Germany", 110); |
现在您可以访问该值(正如Semans已经提到的那样):
1 2
| map["USA"] = 50; // set new value for USA
int power = map["USA"]; // get new value |
编辑:正如评论和其他答案中已经提到的,您当然可以将数据存储在外部文件或任何其他数据存储中。说了这个之后,您可以初始化一个空字典,然后用前面提到的为该存储中的每个记录添加方法填充它。
- +1很好的例子,因为我喜欢它向nasim显示如何加载/填充/和访问字典对象的方式
- 如果这个列表曾经改变过,并且您希望在不占用开发人员时间的情况下维护它,那么您应该从易于编辑的配置文件中加载值。
- 我可能会在一个简单的配置菜单中编写代码,该菜单使用一个网格视图,这样用户就可以在程序中进行更改,而不是在记事本中。
- @cory-配置文件可能是一件很好的事情,所以我并不完全不同意你的看法,但我不能拒绝指出相反的可能性:如果列表不太可能经常更改,可能会占用开发人员更多的时间来决定文件格式,编写代码来分析文件,处理"找不到文件"或分析错误,修复错误,…-)
- @Antinome——这是一个有效的观点,但我还没有遇到一种编程语言,它最多只能用几行代码从JSON文件构建字典。
- @安蒂诺梅:是的,我们完全同意,因为我们都将这个选择的关键放在列表值变化的可能性上。最终由运营商决定他们需要什么,所有这些都是值得考虑的。
这是一个正确的问题,但你需要学习很多东西。许多人都回答了你的问题。我会很恼人的禅宗,告诉你不要问这个问题,因为有一个更大的问题要解决。
不要对此进行硬编码,而是将相关属性存储在N元组(也称为数据库行)中,并使用数据库引擎来管理这两者之间的关系。然后,由于您使用的是C,学习使用LINQ可能是明智的。但是在你做这件事之前,先学习一些数据建模理论,因为数据建模就是你要做的。
- "当你唯一的工具是锤子时,一切看起来都像钉子。"引入数据库似乎是对这个问题的严重破坏。但我同意建议从文件加载数据而不是硬编码的答案。
- 真的!!感谢大家提供所有这些解决方案。我当然有很多东西要学!直到一个月前,我唯一的工具是数组,所以即使是字典也是我的升级版!!:D不过我学得很快,多亏你们了。
- 我会删除关于"以上"答案的讨论。答案可以用多种方式分类。相反,只需说出你的真实意思。"从长远来看,告诉你如何硬编码国家的答案对你没有任何帮助。"
- @Miniragnarok我同意,但我想说两点。一个是建筑,另一个是深层次的教学。我会稍微修改一下。
- @iangoldby-linq2xml在XML上操作,XML可以在单个文件操作中直接加载。它仍然是一个数据库,甚至是可更新的。因此,我拒绝您断言数据库是多余的。
- @Peterwone有许多其他方法可以用一个库调用加载一个简单的键值数据文件,这比Linq等所需的开销要少得多。我的观点是使用合适的工具来完成这项工作。如果该应用程序已经是一个数据库应用程序,那么添加一个新表来保存这个新的配置数据是没有问题的。数据库有它们的用途,但没有金锤这样的东西。
- @iangoldby-正确的工具是TCO最低的工具。由于结构化数据操作是一个解决问题的方法,所以数据库的编写成本、调试成本、维护成本都较低。别再发明轮子了。
是否需要在运行时更新数据?
- 对于"是吗?"问题我同意你的回答,"不?使用开关"不"。在我看来,对196个国家(国家统计局提到了数据量)的转换声明不是一个好的做法。
既然您说您有"对象"称为"国家",并且您已经将您的问题标记为"c",那么您的代码中似乎有两种力量在起作用。一个是,必须引用一个映射,不管它如何有效地实现,都不如引用一个成员变量便宜。另一方面,如果一个国家的所有属性都可以与其他国家的属性在同一个地方找到(面向地图的解决方案确实解决了这一问题),那么这种设置可能会带来一些好处。但是这些力量可以像这样调和:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Country { // Apologies that this sketch is more C++ than C#
public:
Country (string name_, int power_ );
private:
string name ;
int power ;
};
void MakeCountries ()
{
countries .Add(new Country ("USA", 50));
countries .Add(new Country ("Germany", 60));
// ....
} |
制作一个字符串数组来按国名的权力升序存储国名怎么样?实施起来比较简单,每个国家的指数就可以代表它的力量。这是可能的,只有当电源继续计数时。
如果不是,另一种siple方法是将它们实现为链表。如果你愿意,你可以改变。包含两个字段的列表;1表示国家,1表示其他国家。