Instance fields should be initialized in the constructor body or in the class body?

huangapple go评论90阅读模式
英文:

Should instance fields be initialized in the constructor body or in the class body?

问题

在我所有的职业和教育经验中,我一直遵循着不立即在类内定义值的范例,直到对象被创建。我之所以这样做,是因为我看到其他人也这样做。直到今天,我仍然不明白为什么会这样。

如果你不明白我在引用什么,这里有一个大多数人(包括我自己)可能创建对象类的示例。这将是C#,因为我在处理它时产生了这个问题:

public class Thing {
    private List<int> stuff;

    public Thing() {
        stuff = new List<int>();
    }
}

我想知道的是为什么从不这样做的原因是什么:

public class Thing {
    private List<int> stuff = new List<int>();

    public Thing() {
    }
}

就我所理解,每个Thing的实例仍然会有一个独立的stuff实例,因为该值不是静态的。我对编译器的理解并不特别深入,因为我在本科时没有学过这门课程,所以答案可能就是这个原因。那么,为什么不能(或者不应该)使用后一种代码形式呢?不考虑行业标准。

英文:

In all of my professional and educational experience, I have always followed the paradigm of not immediately defining values within a class until the object is created. I did this because I saw others doing it. I still, to this day, do not understand why this is the case.

In case you don't understand what I'm referencing, here is an example of how most people (myself included) may create an object class. This will be C#, since that is what I was working with that drove me to this question:

public class Thing {
    private List<int> stuff;

    public Thing() {
        stuff = new List<int>();
    }
}

What I'm wondering as to why it is not ever done is this:

public class Thing {
    private List<int> stuff = new List<int>();

    public Thing() {
    }
}

As far as I understand, each instance of Thing would still have an independent instance of stuff, as the value is not static. I don't have an exceptional understanding of compilers, as I never took the course in undergrad, so the answer may be that. So why can't (or shouldn't I) use the latter form of code? Industry standards aside.

答案1

得分: 2

两种选择都是有效的(它们可以编译)。

如果我要猜测为什么你经常看到第一种选项,可能与构造函数参数有关。想象一下这个类的变种:

public class Thingy
{
     private List<int> stuff;
     private Gizmo gizmo;

     public Thingy(Gizmo gizmo)
     {
         stuff = new List<int>();
         this.gizmo = gizmo;
     }
}

如果你选择了第二个选项,你可以直接初始化 stuff,但只能从构造函数中分配 gizmo。这会使初始化代码分散,所以作为代码阅读者,你需要查看多个地方才能理解类如何初始化。

使用这里显示的第一种选项,你可以将所有类初始化代码集中在一个地方,使下一个程序员更容易理解类如何初始化。

这在构造函数链接方面变得更加明显:

public class Thingy
{
     private List<int> stuff;
     private Gizmo gizmo;

     public Thingy(Gizmo gizmo) : this(gizmo, new List<int>())
     {
     }

     public Thingy(Gizmo gizmo, List<int> stuff)
     {
         this.stuff = stuff;
         this.gizmo = gizmo;
     }
}

即使有多个构造函数,也只有一个地方初始化对象。

在没有构造函数参数的特殊情况下(如在原始问题中),这两种选择都解决了这个问题。我想很多人(包括我在内)喜欢保持一致性,所以他们选择第一种选项。此外,如果以后决定添加构造函数参数,这也会有所帮助。如果已经使用了第一种选项,你不需要移动类的初始化代码。

英文:

Both alternatives are valid (they compile).

If I were to venture a guess as to why you often see the first option, it may have to do with constructor parameters. Imagine this variation of a class:

public class Thingy
{
     private List&lt;int&gt; stuff;
     private Gizmo gizmo;

     public Thingy(Gizmo gizmo)
     {
         stuff = new List&lt;int&gt;();
         this.gizmo = gizmo;
     }
}

If you'd gone with the second option, you could initialize stuff directly, but you can only assign gizmo from the constructor. This would spread the initialisation code, so that you, as a code reader, have to look in more than one place to understand how the class is initialised.

Using the first option shown here, you centralise all class initialisation code in one place, making it easier for the next programmer to understand how the class gets initialised.

This becomes even more pronounced with constructor chaining:

public class Thingy
{
     private List&lt;int&gt; stuff;
     private Gizmo gizmo;

     public Thingy(Gizmo gizmo) : this(gizmo, new List&lt;int&gt;())
     {
     }

     public Thingy(Gizmo gizmo, List&lt;int&gt; stuff)
     {
         this.stuff = stuff;
         this.gizmo = gizmo;
     }
}

Even with multiple constructors, there's only one place where the object is initialised.

In the special case where there are no constructor parameters (as in the OP), both alternatives solve that problem. I suppose many people (me included) prefer to keep things consistent, so they go for the first option for that reason.

This will furthermore also help if you at a later date decide to add a constructor parameter. If you've already used the first option, you don't have to move the class' initialisation code.

huangapple
  • 本文由 发表于 2023年8月4日 23:12:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837197.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定