3

可能重复:
C#成员变量初始化;最佳实践?
为什么要在构造函数中初始化成员变量?
我应该在构造函数内还是在构造函数外初始化变量

在 Java/C# 中我们通常会看到

public class MyClass {
    private MyObject myObject;

    public MyClass(){
        myObject = new MyObject();
    }
}

代替

public class MyClass {
    private MyObject myObject = new MyObject();

    public MyClass(){

    }
}

如果有的话是什么原因?

4

2 回答 2

1

没有区别,只是风格选择。

在您的示例中,如果您选择第二种方法,则不必提供构造函数,这样可以节省几行代码。

于 2012-08-28T17:34:41.410 回答
1

这归结为其中一条评论中所述的编码偏好。如果编译以下代码

public class TestInitialization
{
    private object test1 = new object();
    private object test2;

    public TestInitialization()
    {
        this.test2 = new object();
    }
}

编译时,实际使用的代码如下

public class TestInitialization
{
    private object test1;
    private object test2;

    public TestInitialization()
    {
        this.test1 = new object();
        this.test2 = new object();
    }
}

所以它们是完全相同的东西,使用你喜欢的任何一个。

编辑:这是一个具有继承类的基类和生成的编译 IL 的示例。

基类

class basetest
{
    private object test1 = new object();
    private object test2;

    public basetest()
    {
        this.test2 = new object();
    }
}

继承类

class testclass : basetest
{
    private object testclass1 = new object();
    private object testclass2;

    public testclass() : base()
    {
        this.testclass2 = new object();
    }
}

生成的 IL 基类

.class private auto ansi beforefieldinit basetest
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: newobj instance void [mscorlib]System.Object::.ctor()
        L_0006: stfld object logtest.basetest::test1
        L_000b: ldarg.0 
        L_000c: call instance void [mscorlib]System.Object::.ctor()
        L_0011: nop 
        L_0012: nop 
        L_0013: ldarg.0 
        L_0014: newobj instance void [mscorlib]System.Object::.ctor()
        L_0019: stfld object logtest.basetest::test2
        L_001e: nop 
        L_001f: ret 
    }


    .field private object test1

    .field private object test2

}

继承类 IL

.class private auto ansi beforefieldinit testclass
    extends logtest.basetest
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: newobj instance void [mscorlib]System.Object::.ctor()
        L_0006: stfld object logtest.testclass::testclass1
        L_000b: ldarg.0 
        L_000c: call instance void logtest.basetest::.ctor()
        L_0011: nop 
        L_0012: nop 
        L_0013: ldarg.0 
        L_0014: newobj instance void [mscorlib]System.Object::.ctor()
        L_0019: stfld object logtest.testclass::testclass2
        L_001e: nop 
        L_001f: ret 
    }


    .field private object testclass1

    .field private object testclass2

}

我觉得我有点困惑。在此示例中,构造函数外部的初始化程序在调用基本构造函数之前首先被初始化。所以无论如何,构造函数之外的初始化器将在构造器内部的初始化器之前被初始化,并且在大多数情况下这应该无关紧要。从技术上讲,它们都被转换为在构造函数中初始化,并且适用以下规则。

  1. 首先运行构造函数之外的所有初始化程序
  2. 调用所有基类构造函数
  3. 构造函数内的所有初始化程序都运行

基本上,编译器会将构造函数之外的所有初始化程序添加到构造函数代码中,然后正常运行。

所以这

public class test : basetest
{
    private object test1 = new object();
    private object test2;

    public test() : base()
    {
        this.test2 = new object();
    }
}

public class basetest
{
    private object basetest1 = new object();
    private object basetest2;

    public basetest()
    {
        this.basetest2 = new object();
    }
}

变成

public class test : basetest
{
    private object test1;
    private object test2;

    public test()
    {
        //prepend everything first
        this.test1 = new object();

        //call base
        base(); //not legal but just an example

        //everything else that was already here
        this.test2 = new object();
    }
}

public class basetest
{
    private object basetest1;
    private object basetest2;

    public basetest()
    {
        //prepend initializers
        this.basetest1 = new object();

        //if there were more base classes, the constructors would be called here

        //do everything else that was already here
        this.basetest2 = new object();
    }
}

希望这更有意义并澄清了一些事情。我知道我在理解某些人说它在构造函数“首先”或“外部”运行时的含义时遇到了问题;它实际上 ALL 都在构造函数内运行,但被调用的顺序受到影响。

于 2012-08-28T17:36:59.803 回答