C# 声明变量-最佳实践

C# 声明变量-最佳实践,c#,.net,C#,.net,我不久前发现(我想再次确认)如果声明一个类级变量,在调用类构造函数或加载之前不应该调用它的构造函数。原因是性能——但是否还有其他理由这样做?这条规则有例外吗 ie:这是我根据我认为最佳实践所做的: public class SomeClass { private PersonObject _person; public SomeClass() { _person = new PersonObject("Smitface"); } } public clas

我不久前发现(我想再次确认)如果声明一个类级变量,在调用类构造函数或加载之前不应该调用它的构造函数。原因是性能——但是否还有其他理由这样做?这条规则有例外吗

ie:这是我根据我认为最佳实践所做的:

public class SomeClass
{
   private PersonObject _person;

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

   public SomeClass()
   {

   }
}
反对:

public class SomeClass
{
   private PersonObject _person;

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

   public SomeClass()
   {

   }
}

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


实际上,这是个人偏好,它们都做相同的事情。

老实说,如果你看一下IL,第二种情况下发生的一切就是编译器将初始化移动到构造函数中


就我个人而言,我喜欢在构造函数中完成所有初始化。如果我正在处理一个一次性原型项目,我不介意将初始化和声明放在同一个位置,但是对于我的“我想保留这个”项目,我会在构造函数中完成所有工作。

我更喜欢尽快初始化变量,因为它可以避免(某些)空错误

编辑:显然在这个简化的示例中没有区别,但是在一般情况下,如果可能的话,我相信在声明类变量时初始化类变量是一种很好的做法。这使得在初始化变量之前无法引用它,从而消除了初始化构造函数中的字段时可能出现的一些错误


当你得到更多的类变量,构造函数中的初始化序列变得更复杂时,如果一个初始化依赖于另一个尚未发生的初始化,那么引入错误就变得更容易了。

这取决于如何使用变量的上下文。自然,常量和static或readonly应该在声明时初始化,否则它们通常应该在构造函数中初始化。这样,您就可以很容易地将设计模式替换为对象的安装方式,而不必担心变量何时初始化。

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

如果在构造函数之外设置变量,则没有可用的错误处理(处理)。虽然在您的示例中没有区别,但在许多情况下,您可能希望进行某种错误处理。在这种情况下,使用第一个选项是正确的

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


出于这个原因,我总是使用选项#1。

我喜欢在构造函数中初始化,因为这样所有的事情都发生在一个地方,而且如果您以后决定创建一个重载构造函数,这会更容易


此外,它还帮助提醒我要在解构器中清理的东西。

后者可以利用延迟实例化,即在引用变量之前它不会初始化变量。

我认为这类问题只是文体问题,所以谁在乎你怎么做呢。语言允许两者兼而有之,所以其他人将两者兼而有之。不要做出错误的假设。

事实上,不管其他人怎么说,初始化是在构造函数内部还是外部都很重要,因为如果对象处于层次结构中(即运行的顺序不同),在对象构造过程中会有不同的行为

请参阅和Eric Lippert,其中更详细地解释了两者之间的语义差异


因此,答案是,在大多数情况下,它不会产生任何影响,当然在性能方面也不会产生任何影响,但在少数情况下,它可能会产生影响,您应该知道原因,并据此做出决定。

您通常应该更喜欢第二种变体。它对代码中的更改更加健壮。假设您添加了一个构造函数。现在您必须记住在那里初始化变量,除非您使用第二个变量


当然,只有在没有令人信服的理由在构造函数初始化中使用(如Discrax所述)时,这才起作用。

有一种称为依赖注入或控制反转(IOC)的常见模式,它正好提供了这两种机制来“注入”依赖对象(如DAL类)进入依赖链最上层的类(来自数据库)

在这个模式中,使用一个ctor,您将

公共类SomeClass
{
私人物品

 public SomeClass(PersonObject person) 

 {      
     per = person;   
 }   
}

private PersonObject Joe=新PersonObject(“Smitface”)

SomeClass MyObj=新的SomeClass(Joe)

例如,现在您可以为生产调用传入一个真正的DAL类
或单元测试方法中的测试DAL类

构造器可能会失败,而你无法处理#2中的错误,这是使用#1的一个很好的理由:在这种情况下,它与风格无关,而是与可靠性有关。选择第一种风格的一个很好的理由。你对“handleing”的拼写让我想起了“乔治纪事”和他对“having”的拼写+1的内存。我相信在使用线程时,初始化构造函数中的成员变量会受到竞争条件的影响,而初始化at声明则作为原子操作运行。您的评论在这里并不适用。无论使用哪种方法,变量都会同时初始化。注释者编辑的注释有一个很好的观点——如果我有一个带有初始值设定项的字段,我知道它将被初始化。如果我在一个有20个构造函数的类中有一个字段,那么在使用变量之前很难确保它已经初始化。埃里克·利珀特的帖子让这一点更加真实。你永远不可能做到