为什么FxCop认为将字段初始化为默认值是不好的?

Pet*_*ter 24 fxcop

在为字段分配默认默认值时(此处为bool的false),FxCop说:

Resolution   : "'Bar.Bar()' initializes field 'Bar.foo' 
               of type 'bool' to false. Remove this initialization 
               because it will be done automatically by the runtime."
Run Code Online (Sandbox Code Playgroud)

现在,我知道代码是int a = 0或bool ok = false正在引入一些冗余,但对我而言,它似乎是一个非常非常好的代码实践,我的老师在我看来坚持正确的代码实践.

不仅性能损失很小,更重要的是:依赖于默认值依赖于每个程序员的知识,使用一段代码,在默认的每种数据类型上.(约会时间?)

说真的,我觉得这很奇怪:应该保护你不要犯下太明显错误的程序,建议在这里制作一个,只是为了提高性能?(我们在这里讨论初始化代码,只执行一次!那些关心那么多的程序员当然可以省略初始化(并且应该使用C或汇编程序:-)).

FxCop在这里犯了一个明显的错误,还是有更多呢?

两个更新:

  1. 这不仅仅是我的观点,而是我在大学(比利时)教过的.并不是说我喜欢使用一个 论证广告verecundiam,而只是为了表明这不仅仅是我的观点.关于那个:

  2. 道歉,我刚刚发现了这个:

    我应该总是/永远/永远不会将对象字段初始化为默认值吗?

Ree*_*sey 12

在某些情况下,可以从中获得显着的性能优势.有关详细信息,请参阅此CodeProject文章.

主要问题是在C#中没有必要.在C++中,事情是不同的,所以许多教授都教导你应该总是初始化.初始化对象的方式在.NET中已更改.

在.NET中,对象始终在构造时初始化.如果添加初始化程序,则可能(典型地)导致变量的双重初始化.无论是在构造函数中还是在内联中初始化它们都会发生这种情况.

此外,由于在.NET中不需要初始化(它总是会发生,即使您没有明确说要初始化为默认值),从可读性的角度来看,添加初始化程序建议您尝试添加具有功能.每一段代码都应该有目的,或者在不必要时删除."额外"代码,即使它是无害的,也表明它存在原因,这降低了可维护性.

  • 对谁或什么不必要?你当然是代码,对于机器的评论也是不必要的,这并不意味着它们是不必要的 (2认同)
  • 与评论的不同之处在于,当我说 int i = 0; 我希望 i 为零,该语句是合乎逻辑的。即使使用具有其他默认值的未来编译器进行编译(对于 int ofcourse 不太可能) (2认同)
  • @ReedCopsey 我重新进行了测试,显然测试是错误的(并且一直都是错误的)。没有性能差异。我在下面发布了我的结果。 (2认同)

Mic*_*ows 5

FxCop必须为每个人提供规则,因此如果此规则不适合您,请将其排除.

现在,我建议如果要显式声明默认值,请使用常量(或静态只读变量)来执行此操作.它比用值初始化更清晰,FXCop不会抱怨.

private const int DEFAULT_AGE = 0;

private int age = 0; // FXCop complains
private int age = DEFAULT_AGE; // FXCop is happy

private static readonly DateTime DEFAULT_BIRTH_DATE = default(DateTime);

private DateTime birthDate = default(DateTime); // FXCop doesn't complain, but it isn't as readable as below
private DateTime birthDate = DEFAULT_BIRTH_DATE; // Everyone's happy
Run Code Online (Sandbox Code Playgroud)


Dan*_*ker 5

Reed Copsey说,指定字段的默认值会影响性能,他指的是2005年的测试.

public class A
{
    // Use CLR's default value
    private int varA;
    private string varB;
    private DataSet varC;
}

public class B
{
    // Specify default value explicitly
    private int varA = 0;
    private string varB = null;
    private DataSet varC = null;
}
Run Code Online (Sandbox Code Playgroud)

现在已经有8年和4个版本的C#和.NET了,我决定在.NET Framework 4.5和C#5下重复该测试,使用Visual Studio 2012进行默认优化编译为Release.我很惊讶地看到仍然存在性能差异在使用默认值显式初始化字段而不指定默认值之间.我原本期望后来的C#编译器能够优化这些常量赋值.

No init: 512,75    Init on Def: 536,96    Init in Const: 720,50
Method No init: 140,11    Method Init on Def: 166,86

(其余的)

所以我在类的构造函数A和B本测试中查看,两者都是空的:

.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void [mscorlib]System.Object::.ctor()
    IL_0006: ret
} // end of method .ctor
Run Code Online (Sandbox Code Playgroud)

我能不能找到在IL一个原因,明确分配默认常量值的字段会消耗更多的时间.显然C#编译器确实优化了常量,我怀疑它总是这样做.

所以,那么测试一定是错的......我交换了类的内容,A并B交换了结果字符串中的数字,并重新进行了测试.和你瞧现在突然指定默认值更快.

No init: 474,75    Init on Def: 464,42    Init in Const: 715,49
Method No init: 141,60    Method Init on Def: 171,78

(其余的)

因此,我得出结论,C#编译器正确地优化了为字段分配默认值的情况.它没有性能差异!


现在我们知道性能确实不是问题.而且我不同意Reed Copsey的声明 " '额外'代码,即使它是无害的,也表明它存在原因,这降低了可维护性. "并且同意Anders Hansson的观点:

考虑长期维护.

  • 保持代码尽可能明确.
  • 如果您不需要,请不要依赖特定于语言的方法进行初始化.也许新版本的语言会有不同的用途?
  • 未来的程序员会感谢你.
  • 管理层会感谢你.
  • 为什么甚至一点点混淆东西呢?

未来的维护者可能来自不同的背景.这真的不是什么是"正确的",而是从长远来看更容易实现的目标.