【问题标题】:Declaring variables - best practices声明变量 - 最佳实践
【发布时间】:2008-10-30 08:48:51
【问题描述】:

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

即:这是我根据我认为的最佳做法所做的:

public class SomeClass
{
   private PersonObject _person;

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

反对:

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

   public SomeClass()
   {

   }
}

【问题讨论】:

    标签: c# .net


    【解决方案1】:

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

    Nescio 谈到了如果有一些构造函数失败,这会对您的应用程序产生什么影响。

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

    【讨论】:

    • 构造函数可能失败并且您无法处理 #2 中的错误这一事实是使用 #1 的一个非常好的理由:在这种情况下,它不是关于样式,而是关于可靠性。
    • 选择第一种风格的好理由。
    • 您对“处理”的拼写让我想起了“乔治编年史”和他对“避风港”的拼写。为记忆+1。
    • 我相信在使用线程时在构造函数中初始化你的成员变量会受到竞争条件的影响,而在声明时初始化是作为原子操作运行的。
    【解决方案2】:

    老实说,如果您查看 IL,在第二种情况下发生的所有事情都是编译器将初始化移动到您的构造函数。

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

    【讨论】:

      【解决方案3】:

      实际上,不管其他人怎么说,你的初始化是在构造函数内部还是外部可能很重要,因为如果对象在层次结构中,则在对象构造期间会有不同的行为(即事物运行的顺序不同)。

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

      所以答案是,在大多数情况下,它没有任何区别,而且在性能方面肯定没有任何区别,但在少数情况下,它可以有所作为,您应该知道原因,并据此做出决定。

      【讨论】:

        【解决方案4】:

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

        在这个模式中,使用 ctor,你会

        公共类 SomeClass
        {
        每个私有的 PersonObject;

         public SomeClass(PersonObject person) 
        
         {      
             per = person;   
         }   
        

        }

        private PersonObject Joe = new PersonObject("Smitface");

        SomeClass MyObj = new SomeClass(Joe);

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 你永远不能只看构造函数就做出假设,因为语言允许你用另一种方式来做。如果您以另一种方式导入您去年编写的一些代码怎么办?希望你不要切换模式。 (在这种情况下,生成的 IL 似乎是等价的,但可能还有其他)
          【解决方案6】:

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

          当然,这仅在没有令人信服的理由使用构造函数内初始化(如 discorax 所述)时才有效。

          【讨论】:

            【解决方案7】:

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

            这真的是个人喜好,他们都做同样的事情。

            【讨论】:

              【解决方案8】:

              我喜欢在构造函数中进行初始化,因为这一切都发生在一个地方,还因为如果您决定稍后创建一个重载的构造函数,它会更容易。

              此外,它有助于提醒我要在解构器中清理的内容。

              【讨论】:

                【解决方案9】:

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

                【讨论】:

                  【解决方案10】:

                  我认为这种类型的问题只是文体问题,所以谁在乎你是怎么做的。语言允许两者,所以其他人会同时做。不要做出错误的假设。

                  【讨论】:

                    【解决方案11】:

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

                    【讨论】:

                    • 静态构造函数?在这个例子中我没有看到任何静态的东西。
                    【解决方案12】:

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

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

                    随着您获得更多类变量并且构造函数中的初始化序列变得更加复杂,引入错误变得更加容易,其中一个初始化依赖于另一个尚未发生的初始化。

                    【讨论】:

                    • 您的评论在这里并不适用。无论使用哪种方法,变量都会同时初始化。
                    • 评论者编辑的评论有一个好点——如果我有一个带有初始化器的字段,我知道它将被初始化。如果我在一个具有 20 个构造函数的类中有一个字段,则更难确保变量在使用之前已初始化。 Eric Lippert 的帖子使这一点更加真实。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-07-19
                    • 2013-11-26
                    相关资源
                    最近更新 更多