声明变量 - 最佳实践

5

我在一段时间前发现(并希望再次确认)如果你声明了一个类级变量,直到类构造函数或加载已被调用之前,你不应该调用它的构造函数。原因是性能 - 但有没有其他理由来做或不做这件事?有没有例外?

例如:根据我认为的最佳实践,我会这样做:

public class SomeClass
{
   private PersonObject _person;

   public SomeClass()
   {
      _person = new PersonObject("Smitface");
   }
}

相对于:

public class SomeClass
{
   private PersonObject _person = new PersonObject("Smitface");

   public SomeClass()
   {

   }
}
12个回答

12

如果您在构造函数外设置变量,则没有错误处理可用。尽管在您的示例中没有任何区别,但有很多情况下您可能需要进行某种形式的错误处理。在这种情况下,使用第一种选项是正确的。

Nescio讨论了如果构造函数出现故障,这将对您的应用程序产生什么影响。

因此,我总是使用选项#1。


构造函数可能失败且无法在#2中处理错误,这是使用#1的非常好的理由:在这种情况下,重点不在于风格而在于可靠性。 - Jared Updike
选择第一种风格的好理由。 - Esteban Brenes
1
你拼写"handleing"让我想起了"乔治的编年史"和他拼写"havening"的方式。+1 记忆。 - StingyJack
1
我认为在构造函数内初始化成员变量在使用线程时会存在竞争条件,而在声明时初始化则作为原子操作运行。 - Haoest

6

说实话,如果你看一下IL(Intermediate Language),在第二种情况下发生的一切都是编译器为你将初始化移动到构造函数中。

个人而言,我喜欢在构造函数中完成所有初始化。如果我正在处理一个临时原型项目,我不介意在同一位置进行初始化和声明,但对于我想要保留的项目,我会在构造函数中完成全部操作。


4
实际上,尽管其他人已经说过,初始化是在构造函数内部还是外部可能很重要,因为如果对象在层次结构中(即事物运行的顺序不同),在对象构造期间会有不同的行为。
请参阅Eric Lippert的这篇文章这篇文章,更详细地解释了两者之间的语义差异。
因此,在大多数情况下,它并不会产生任何影响,而且在性能方面肯定不会产生任何影响,但在少数情况下,它可能会产生影响,您应该知道原因,并基于此做出决策。

2

有一种常见的模式叫做依赖注入或控制反转(IOC),它为“注入”一个依赖对象(比如一个DAL类)到一个更高级别的类(离数据库更远)中提供了这两个机制。

在这个模式中,使用构造函数,你可以:

public class SomeClass
{
private PersonObject per;

 public SomeClass(PersonObject person) 

 {      
     per = person;   
 }   

}

私有的PersonObject Joe = new PersonObject("Smitface");

SomeClass MyObj = new SomeClass(Joe);

现在你可以传入一个真正的DAL类来进行生产调用,或者在单元测试方法中传入一个测试DAL类...


1

这取决于变量的使用上下文。通常,常量和静态或只读变量在声明时应进行初始化,否则它们通常应该在构造函数中进行初始化。这样一来,您可以相对轻松地更改对象实例化的设计模式,而不必担心变量何时被初始化。


仅通过构造函数,你不能做出任何假设,因为语言允许你用另一种方式实现。如果你以另一种方式导入去年编写的代码,会怎样呢?希望你不会切换模式。(在这种情况下,生成的中间语言是等效的,但可能存在其他情况) - Dustin Getz

1
通常情况下,您应该更喜欢使用第二种变体。它对代码的变化更加健壮。假设您添加了一个构造函数。现在,除非您使用第二种变体,否则您必须记住在那里初始化变量。
当然,这仅适用于没有强制使用构造函数初始化的情况(如discorax所提到的)。

0

我更喜欢后者,只是因为我觉得它更整洁。

这其实是个人偏好,它们都能完成同样的任务。


0

第一种声明实际上更加简洁。第二种声明隐藏了构造函数在静态构造函数中初始化类的事实。如果由于任何原因构造函数失败,整个类型在应用程序的其余部分中将无法使用。


静态构造函数?我在这个例子中没有看到任何静态的东西。 - Neil

0

我喜欢在构造函数中初始化,因为这样所有的操作都在一个地方完成,而且如果以后决定创建重载构造函数,这样做会更容易。

此外,它有助于提醒我需要在析构函数中清理的事情。


0

后者可以利用惰性实例化,即在变量被引用之前不会初始化它


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接