2012-12-29 100 views
7

可能重复:
Best Practice: Initialize class fields in constructor or at declaration?初始化变量:直接或在构造函数中?

大部分时间里,我看到初始化变量这样

public class Test 
{ 
    private int myIntToInitalize; 

    public Test() 
    { 
     myIntToInitalize = 10; 
    } 
} 

从我的角度来看的方式,这是最初始化变量的一般方法。书籍,博客和.NET的内部实现中的大部分代码都与我的例子相同。

最近我看到人们直接进行初始化,所以没有在构造函数中设置值。

public class Test 
{ 
    private int myIntToInitalize = 10; 
} 

从角度来看,初始化和声明变量或在构造函数中初始化变量没有区别。

除了最佳实践和代码行的长度,直接初始化变量的好处在哪里,并且存在细微差别?

+1

可能的复制,HTTP://计算器。 com/questions/24551/best-practice-initialize-class-fields-in-constructor-or-at-declaration and http://stackoverflow.com/questions/298183/c-sharp-member-variable-initialization-best-练习 – Cyral

+0

http://stackoverflow.com/a/14083981/922198 –

回答

15

在某些情况下有一个潜在的显着差异。

实例初始值设定项执行之前执行基类构造函数。因此,如果基类构造函数调用在派生类中重写的任何虚方法,该方法将会看到不同。 通常但是这不应该是一个明显的差异 - 因为在构造函数中调用虚拟方法几乎总是一个坏主意。

在清晰度方面,如果您在声明点初始化变量,则会清楚地表明值不是取决于任何构造函数参数。另一方面,保持所有初始化在一起也有助于可读性,IMO。我会尝试以确保在任何可能的情况下,如果您有多个构造函数,它们都将委托给一个“主”构造函数,该构造函数执行所有“真实”初始化 - 这意味着您只能将这些指派放在一个位置。

示例代码来演示的区别:

using System; 

class Base 
{ 
    public Base() 
    { 
     Console.WriteLine(ToString()); 
    } 
} 

class Derived : Base 
{ 
    private int x = 5; 
    private int y; 

    public Derived() 
    { 
     y = 5; 
    } 

    public override string ToString() 
    { 
     return string.Format("x={0}, y={1}", x, y); 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     // Prints x=5, y=0 
     new Derived(); 
    } 
} 
4

我不知道有任何细微的差异。我通常喜欢把所有的初始化放在构造函数中,因为我认为它使得代码更具可读性。但这更多的是一种风格选择和个人喜好。我没有听说过有技术理由来证明这一点。我怀疑是否有任何性能影响。

静态和最终的常量是不同的问题。我初始化这些内联。

4

当一个实例被构造时,在声明时初始化的任何变量将在构造函数运行之前被初始化。如果您没有访问这些变量或在构造函数中使用它们的值,那么这两种方法之间没有功能差异。

+4

它们甚至在基类构造函数运行之前运行。 – CodesInChaos

+0

当你处理虚拟方法时,这变得更加重要。从构造函数中调用虚拟方法并不是一个好习惯,但是如果您从Base构造函数调用了VirtualMethod,并且Derived类覆盖了它,您会发现在执行虚拟方法之前将会“执行”任何变量初始值设定项,但Derived构造函数将不会被执行。 附加信息:http://blogs.msdn.com/b/ericlippert/archive/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one。 aspx http://www.yoda.arachsys.com/csharp/constructors.html –

2

为您简单的例子,它只是一个风格问题。

涉及继承时有细微差别。例如字段初始化器,执行的顺序是派生类字段初始化器,基类字段初始化器,基类构造器,派生类构造器。

拿这个例子:

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     new Derived(); 
    } 
} 

public class Base 
{ 
    private int x = BaseInitializer(); 

    public Base() 
    { 
      Console.WriteLine("Base ctor"); 
    } 

    private static int BaseInitializer() 
    { 
     Console.WriteLine("BaseInitializer"); 
     return 0; 
    } 
} 

public class Derived : Base 
{ 
    private int x = DerivedInitializer(); 

    public Derived() : base() 
    { 
     Console.WriteLine("Derived ctor"); 
    } 

    private static int DerivedInitializer() 
    { 
     Console.WriteLine("DerivedInitializer"); 
     return 0; 
    } 
} 

它打印:

  • DerivedInitializer
  • BaseInitializer
  • 基地男星
  • 衍生男星
0
public class Test 
{ 
    private int myIntToInitalize = 10; 
    public Test() 
    { 

    } 

    public Test(string x) 
    { 
    } 
} 

public class Test2 
{ 
    private int myIntToInitalize; 
    public Test2() 
    { 
     this.myIntToInitalize = 10; 
    } 

    public Test2(string x) 
    { 
    } 
} 

类Test1每个对象实例将myIntToInitalize设置为10, 但不是在类Test2时,当你调用需要1参数的构造函数。

2

可以说我们编译下面的代码,在优化的释放&构建

namespace ConsoleApplication4 
{ 

    public class Test1 
    { 
     private int myIntToInitalize; 

     public Test1() 
     { 
      myIntToInitalize = 10; 
     } 
    } 

    public class Test2 
    { 
     private int myIntToInitalize = 10; 
    } 


    static class Program 
    { 

     private static void Main() 
     { 
     } 


    } 

} 

的IL指令为类测试1

.class public auto ansi beforefieldinit Test1 
    extends [mscorlib]System.Object 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
     .maxstack 8 
     L_0000: ldarg.0 
     L_0001: call instance void [mscorlib]System.Object::.ctor() 
     L_0006: ldarg.0 
     L_0007: ldc.i4.s 10 
     L_0009: stfld int32 ConsoleApplication4.Test1::myIntToInitalize 
     L_000e: ret 
    } 


    .field private int32 myIntToInitalize 

} 

的IL指令类的Test2

.class public auto ansi beforefieldinit Test2 
    extends [mscorlib]System.Object 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
     .maxstack 8 
     L_0000: ldarg.0 
     L_0001: ldc.i4.s 10 
     L_0003: stfld int32 ConsoleApplication4.Test2::myIntToInitalize 
     L_0008: ldarg.0 
     L_0009: call instance void [mscorlib]System.Object::.ctor() 
     L_000e: ret 
    } 


    .field private int32 myIntToInitalize 

} 

非常明显,两个类都有相同数量的IL插入唯一的区别是,

变量在调用Class Test1中的:: ctor()之前被初始化; 和 变量在Class Test2中调用:: ctor()后被初始化;

注意:性能方面既可使用类将执行相同的,因为他们有相同的数字&型IL指令,只是IL指令的执行顺序是不同

相关问题