Item 12: Prefer Member Initializers to Assignment Statements 使用成员初始化,避免赋值声明

  • Classes often have more than one constructor. Over time, it’s easy for the member variables and the constructors to get out of sync. The best way to make sure this doesn’t  happen is to initialize variables where you declare them instead of in the body of every constructor. You should utilize the initializer syntax for both static and instance variables.
    Constructing member variables when you declare that variable is natural in C#. Just initialize the variable when you declare it:
    总是有很多构造器,时间长了,成员函数容易失去同步。最好的方法就是在你声明它们的地方进行初始化,而不是在构造体。初始化静态和实例变量 Classes often have more than one constructor. Over time, it’s easy for the member variables and the constructors to get out of sync. The best way to make sure this doesn’t  happen is to initialize variables where you declare them instead of in the body of every constructor. You should utilize the initializer syntax for both static and instance variables.Constructing member variables when you declare that variable is natural in C#. Just initialize the variable when you declare it:
    public class MyClass
    {
      // declare the collection, and initialize it.
      private List<string> labels = new List<string>();
    }
  • 使用初始化是避免类型中出现未初始化变量的最简单的方法。但是它不是完美的,下面来介绍3种不适合的情况。Using initializers is the simplest way to avoid uninitialized variables in your types, but it’s not perfect. In three cases, you should not use the initializer syntax.
  1. 当你初始化一个对象为0或者null。默认的系统初始化会在你任何代码执行之前,将所有对象设置为0。这是一个在CPU底层的操作。所有其他的0操作都是多余的。但是c#编译器依然会将多余的0再次存储,这是低效的。 Any extra 0 initialization on your part is superfluous. The C# compiler dutifully adds the extra instructions to set memory to 0 again. It’s not wrong—it’s just inefficient. In fact, when value types are involved, it’s very inefficient.
    MyValType myVal1; // initialized to 0
    MyValType myVal2 = new MyValType(); // also 0
    这两个声明的变量都是0:第一个的结果是因为设置内存的原因,第二个通过IL指令initobj,这将导致对myVal2进行装箱和拆箱操作。
  2. You cannot wrap the initializers in a try block.
  3. 第三个低效的原因来源于你为同一个对象创造多个初始化。
  4. public class MyClass2
    {
      // declare the collection, and initialize it.
      private List<string> labels = new List<string>();
      MyClass2()
      {
      }
      MyClass2(
    int size)
      {
        labels
    = new List<string>(size);
      }
    }

    当你创建一个新的MyClass2,指定容器的大小的时候,你新建了两个list。一个立刻被GC了。

Item 13: Use Proper Initialization for Static Class Members 对静态类成员使用正确的初始化方法

  • 在一个类型的任何实例初始化以前,你应该初始化它的静态成员变量。在C#中你可以使用静态的初始化器和静态构造函数来实现这个目的。一个类的静态构造函数是一个与众不同的,它在所有的方法,变量或者属性访问前被执行。你可以用这个函数来初始化静态成员变量,强制使用单例模式,或者实现其它任何在类型的实例可用前应该完成的工作。你不能用任何的实例构造函数,其它特殊的私有函数, 或者任何其它习惯方法来初始化一个变量。you should initialize static member variables in a type before you create any instances of that type. C# lets you use static initializers and a static constructor for this purpose. A static constructor is a special function that executes before any other methods, variables, or properties defined in that class are accessed for the first time. You use this function to initialize static variables, enforce the singleton pattern, or perform any other necessary work before a class is usable. You should not use your instance constructors, some special private function, or any other idiom to initialize static variables.
    public class MySingleton
    {
      private static readonly MySingleton theOneAndOnly =new MySingleton();
      public static MySingleton TheOnly
      {
        get { return theOneAndOnly; }
      }
      private MySingleton()
      {
      }
      // remainder elided
    }
    这个单粒模式就是这么简单,除非你有更复杂的逻辑来初始化单例。
    public class MySingleton2
    {
      private static readonly MySingleton2 theOneAndOnly;
      static MySingleton2()
      {
        theOneAndOnly
    = new MySingleton2();
      }

      public static MySingleton2 TheOnly
      {
        get { return theOneAndOnly; }
      }
      private MySingleton2()
      {
      }
      // remainder elided
    }
    就像实例初始化器,静态初始化器在任何静态构造器调用之前调用。CLR在你的type第一次被访问是就自动调用了静态构造器(在appmomain),你只能定义一个静态构造器,而且不能有参数。因为静态构造函数是CLR调用的,你必须十分注意异常的产生。如果在静态构造函数里产生了异常,CLR将会直接终止你的应用程序。正因为异常,静态构造函数常常代替静态预置方法。如果你使用静态预置方法,你自己不能捕获异常。做为一个静态的构造,你可以这样
    static MySingleton2()
    {
      try
      {
        theOneAndOnly
    = new MySingleton2();
      }
      catch
      {
        // Attempt recovery here.
      }
    }

     

  • Static initializers and static constructors provide the cleanest, clearest way to initialize static members of your class. They are easy to read and easy to get correct. They were added to the language to specifically address the difficulties involved with initializing static members in other languages.

ps:最近要考试了,还要CET6....实在不想复习(应该说是预习),在医学院这样的BIRD学校只能做些不愿意做的事情,来博客园转转,顺手对EffectiveCSharp4.0做个摘要。