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

时间:2009-04-08 17:21:32

标签: 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."

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

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

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

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

  

两次更新:

     
      
  1. 这不仅仅是我的意见,而是我在大学里所教的内容   (比利时)。不是说我喜欢用   argumentum ad verecundiam,但是   只是为了表明它不仅仅是我的   意见。关于那个:

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

         

    Should I always/ever/never initialize object fields to default values?

  4.   

6 个答案:

答案 0 :(得分:12)

在某些情况下,可以从中获得显着的性能优势。有关详细信息,请see this CodeProject article.

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

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

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

答案 1 :(得分: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

答案 2 :(得分:5)

Reed Copsey said指定字段的默认值会影响效​​果,并且他引用a test from 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;
}

现在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

the rest)功能

所以我在这个测试中窥视了类AB的构造函数,而这两个都是空的:

.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

我可以在IL中找到原因为什么明确地为字段分配默认常量值会消耗更多时间。显然C#编译器 优化了常量,我怀疑它总是这样做。

那么,测试一定是错的......我交换了类AB的内容,交换了结果字符串中的数字,然后重新进行了测试。现在突然指出指定默认值

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

the rest)功能

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


现在我们知道性能确实是而不是的问题。我不同意Reed Copsey's statement'额外'代码,即使它是无害的,也表明它存在原因,这会降低可维护性。”并同意{{3}在此:

  

考虑长期维护。

     
      
  • 尽可能明确地保持代码。
  •   
  • 如果您不需要,请不要依赖语言特定的方式进行初始化。也许这种语言的新版本会以不同的方式工作?
  •   
  • 未来的程序员会感谢你。
  •   
  • 管理层会感谢你。
  •   
  • 为什么甚至一点点混淆了什么呢?
  •   
     

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

答案 3 :(得分:3)

FX Cop认为它添加了不必要的代码,不必要的代码也很糟糕。我同意你的意见,我希望看到它的设定,我认为它更容易阅读。

我们遇到的类似问题是,出于文档原因,我们可能会创建一个像

这样的空构造函数
/// <summary>
/// a test class
/// </summary>
/// <remarks>Documented on 4/8/2009  by richard</remarks>
public class TestClass
{
    /// <summary>
    /// Initializes a new instance of the <see cref="TestClass"/> class.
    /// </summary>
    /// <remarks>Documented on 4/8/2009  by Bob</remarks>
    public TestClass()
    {
        //empty constructor
    }        
}

编译器会自动创建此构造函数,因此FX警告会抱怨,但我们的sandcastle文档规则要求记录所有公共方法,因此我们只是告诉fx警察不要抱怨它。

答案 4 :(得分:2)

它并不依赖于每个程序员都知道某些本地定义的“公司标准”,这些标准可能会随时改变,而是在标准中正式定义的内容中。你不妨说“不要使用x++,因为这依赖于每个程序员的知识。

答案 5 :(得分:2)

你必须记住,FxCop规则只是指导原则,它们不是牢不可破的。它甚至在页面上说明了您提到的规则(http://msdn.microsoft.com/en-us/library/ms182274(VS.80).aspx,强调我的规则):

何时排除警告

如果构造函数调用将字段初始化为非默认值的相同或基类中的另一个构造函数,则从此规则中排除警告。 如果性能和代码维护不是优先级,也可以安全地从此规则中排除警告,或完全禁用该规则。

现在,规则并不完全错误,但就像它说的那样,这不是你的优先考虑,所以只需禁用该规则。