不断滥用?

我在一些具有以下常量的C#项目中遇到了一堆代码:

const int ZERO_RECORDS = 0; const int FIRST_ROW = 0; const int DEFAULT_INDEX = 0; const int STRINGS_ARE_EQUAL = 0; 

有没有人见过这样的东西? 有没有办法合理化使用常量来表示语言结构? IE:C#在数组中的第一个索引位于第0位。我认为如果开发人员需要依赖常量来告诉他们语言是0,那么手头有一个更大的问题。

这些常量的最常见用法是处理数据表或“for”循环。

我是不是觉得这些是代码味道? 我觉得这些并不比以下更好:

 const int ZERO = 0; const string A = "A"; 

滥用,恕我直言。 “零”只是其中的基础之一。

虽然STRINGS_ARE_EQUAL可能很简单,但为什么不“.Equals”?

接受限制使用魔法数字?

我是不是觉得这些是代码味道? 我觉得这些并不比以下更好:

比较以下内容:

 if(str1.CompareTo(str2) == STRINGS_ARE_EQUAL) ... 

 if(str1.CompareTo(str2) == ZERO) ... if(str1.CompareTo(str2) == 0) ... 

哪一个更直接的意义?

这肯定是代码味道。

意图可能是为代码添加“可读性”,但是在我看来这样的事情实际上会降低代码的可读性。

有些人认为程序中的任何原始数字都是“神奇数字”。 我已经看到编码标准,基本上说你不能只是在程序中写一个整数,它必须是一个const int。

我是不是觉得这些是代码味道? 我觉得这些并不比以下更好:

const int ZERO = 0;

const int A =’A’;

可能有点嗅觉,但肯定比ZERO = 0和A =’A’好。 在第一种情况下,它们定义了逻辑常量,即具有具体值实现的一些抽象概念(字符串相等)。

在您的示例中,您定义了文字常量 – 变量表示值本身。 如果是这种情况,我认为枚举是首选,因为它们很少是奇异值。

这是明确的错误编码。

我说常量应该只在需要的地方使用,以后某些事情可能发生变化。 例如,我有很多“配置”选项,如SESSION_TIMEOUT定义它应该保持不变,但也许它可以在以后调整。 我不认为ZERO可以在路上调整。

此外,对于幻数,不应包括零。

我觉得这个信念有点奇怪,因为我会说这样的事情会走得太远

 //input is FIELD_xxx where xxx is a number input.SubString(LENGTH_OF_FIELD_NAME); //cut out the FIELD_ to give us the number 

你应该看看thedailywtf上的一些东西

One2Pt20462262185th

企业SQL

我认为有时人们盲目地遵循“编码标准” ,即“不要使用硬编码值,将它们定义为常量,以便在需要更新时更容易管理代码” – 这对于以下内容来说是公平的:

 const in MAX_NUMBER_OF_ELEMENTS_I_WILL_ALLOW = 100 

但是没有意义:

 if(str1.CompareTo(str2) == STRINGS_ARE_EQUAL) 

因为每当我看到这段代码时,我都需要搜索STRINGS_ARE_EQUAL定义的内容 ,然后检查文档是否正确。

相反,如果我看到:

 if(str1.CompareTo(str2) == 0) 

我跳过步骤1(搜索STRINGS_ARE...被定义为)并且可以检查规格0表示什么值。

你会正确地想用Equals()替换它,并在你只对一种情况感兴趣的情况下使用CompareTo() ,例如:

 switch (bla.CompareTo(bla1)) { case IS_EQUAL: case IS_SMALLER: case IS_BIGGER: default: } 

如果合适,使用if/else语句(不知道CompareTo()返回…)

我仍然会检查你是否根据规格正确定义了值。

这当然是不同的,如果规范定义像ComparisonClass::StringsAreEqual值或类似的东西(我只是使那一个),那么你不会使用0但适当的变量。

所以它取决于,当你特别需要访问数组中的第一个元素时, arr[0]arr[FIRST_ELEMENT]更好,因为我仍然会检查你所定义的FIRST_ELEMENT因为我不会相信你,它可能是不同的东西比0 – 例如你的0元素是dud,真正的第一个元素存储在1 – 谁知道。

我会寻找代码味道。 如果需要这些常量,请将它们放入枚举中:

 enum StringEquality { Equal, NotEqual } 

(但我怀疑STRINGS_ARE_EQUALstring.Compare返回的string.Compare ,所以黑客返回枚举可能会更加冗长。)

编辑: SHOUTING_CASE也不是特别的.NET风格的命名约定 。

我不知道我是否会称它们为气味,但它们看起来似乎是多余的。 虽然DEFAULT_INDEX实际上可能有用。

重点是避免神奇的数字和零并不是真的神奇。

这个代码是你办公室里的东西还是你下载的东西?

如果它在办公室,我认为如果人们随机放置常数,那么管理就会出现问题。 在全球范围内,除非每个人都清楚地了解或同意这些常数的用途,否则不应该有任何常数。

理想情况下,在C#中,您需要创建一个包含每个其他类全局使用的常量的类。 例如,

 class MathConstants { public const int ZERO=0; } 

然后在后面的课程中,例如:

 .... if(something==MathConstants.ZERO) ... 

至少我就是这样看的。 通过这种方式,每个人都可以理解这些常量甚至没有阅读任何其他内容。 这会减少混乱。

使用常量我通常会想到四个原因:

  1. 作为可能在未来合理变化的值的替代(例如, IdColumnNumber = 1 )。
  2. 作为可能不易理解或有意义的价值的标签(例如FirstAsciiLetter = 65 ),
  3. 作为键入冗长或难以键入值的较短且不易出错的方式(例如, LongSongTitle = "Supercalifragilisticexpialidocious"
  4. 作为难以记忆的值的记忆辅助(例如, PI = 3.14159265

对于您的特定示例,以下是我如何判断每个示例:

 const int ZERO_RECORDS = 0; // almost definitely a code smell const int FIRST_ROW = 0; // first row could be 1 or 0, so this potentially fits reason #2, // however, doesn't make much sense for standard .NET collections // because they are always zero-based const int DEFAULT_INDEX = 0; // this fits reason #2, possibly #1 const int STRINGS_ARE_EQUAL = 0; // this very nicely fits reason #2, possibly #4 // (at least for anyone not intimately familiar with string.CompareTo()) 

所以,我会说,不,这些并不Zero = 0A = "A"

如果零表示零以外的东西(在这种情况下为STRINGS_ARE_EQUAL)那么那就是神奇的。 为它创建一个常量是可以接受的,并使代码更具可读性。

创建一个名为ZERO的常量是毫无意义的,浪费手指能量!

闻到一点,但我可以看到这种情况有意义的情况,特别是如果你有程序员一直从语言切换到语言。

例如,MATLAB是单索引的,所以我可以想象有人厌倦了在切换语言时犯下一个错误,并在C ++和MATLAB程序中定义DEFAULT_INDEX来抽象差异。 不一定优雅,但如果这是它需要的……

对,你要问这个气味年轻的代码战士。 但是,这些命名常量来自编码实践,远远超过Visual Studio的曙光。 它们可能是多余的,但你可能比理解公约的起源更糟糕。 想想NASA电脑,回来的时候……

您可能会在跨平台的情况下看到类似这样的内容,您可以将该文件与适合该平台的常量集一起使用。 但可能不是这些实际例子。 这看起来像COBOL编码器试图使他的C#看起来更像英语(没有针对COBOL编码器的攻击)。

使用常量来表示抽象值是可以的,但用你自己的语言表示构造则是另一种。

const int FIRST_ROW = 0没有意义。

const int MINIMUM_WIDGET_COUNT = 0更有意义。

你应该遵循编码标准的假设是有道理的。 (也就是说,编码标准在组织内是推定正确的。)在不满足推定时严格遵循编码标准是没有意义的。

因此,我同意早期的海报,一些臭味的常数可能是因为遵循编码标准(“无魔数”)而无例外。 这就是问题所在。