Effective C#之12:Prefer Variable Initializers to Assignment Statements

rel="File-List" href="file:///C:%5CDOCUME%7E1%5CHelios%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml"> rel="themeData" href="file:///C:%5CDOCUME%7E1%5CHelios%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx"> rel="colorSchemeMapping" href="file:///C:%5CDOCUME%7E1%5CHelios%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml">

Item 12: Prefer Variable 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 synch. 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 assign a value:

在声明一个变量的时候,就构建成员变量,在C#里面是很自然的事情,仅仅就是赋一个值:

  1.     public class MyClass
  2.     {
  3.         // declare the collection, and initialize it.
  4.         private ArrayList coll = new ArrayList();
  5.     }

Regardless of the number of constructors you eventually add to the MyClass type, _coll will be initialized properly. The compiler generates code at the beginning of each constructor to execute all the initializers you have defined for your instance member variables. When you add a new constructor, _coll gets initialized. Similarly, if you add a new member variable, you do not need to add initialization code to every constructor; initializing the variable where you define it is sufficient. Equally important, the initializers are added to the compiler-generated default constructor. The C# compiler creates a default constructor for your types whenever you don't explicitly define any constructors.

由于忽略了逐渐加入到MyClass类型中的构造函数的数目,cool被会很好的进行初始化。每个构造函数中一开始执行你定义的所有初始化,编译器就会为所有的实例成员变量生成了代码。当你加入一个新的构造函数时,cool已经被初始化了。同理,如果你加入一个新的成员变量,那么就没必要向每个构造函数里面加入初始化代码;在你定义变量的地方就进行初始化,足够了。同样重要的是,初始化器被加到了编译器生成的默认构造函数中。当你没有显式的定义任何构造函数的时候,C#编译器会为你的类型创建默认的构造函数。

Initializers are more than a convenient shortcut for statements in a constructor body. The statements generated by initializers are placed in object code before the body of your constructors. Initializers execute before the base class constructor for your type executes, and they are executed in the order the variables are declared in your class.

初始化器不仅仅是构造函数体里面表达式的一个便捷的快捷方式。在对象代码里面,初始化器生成的表达式,放置在构造函数体的前面。初始化器在基类构造函数执行前被执行,它们被执行的顺序就是在类里被声明的顺序。

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. The first is when you are initializing the object to 0, or null. The default system initialization sets everything to 0 for you before any of your code executes. The system-generated 0 initialization is done at a very low level using the CPU instructions to set the entire block of memory to 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.

使用初始化器是避免在你的类型里面出现未初始化变量的最简单方法,但是不够完美。有3种情况,不应该使用初始化语法。第一个,当你将对象初始化为0或者null的时候。在任何代码被执行之前,默认的系统初始化将一切设置为0。系统生成的0初始化是在一个很低的级别被完成的,使用CPU指令结构将整块的内存设置为0。你做得任何额外的0初始化都是多余的。C#编译器很负责的加入额外的指令,再次将内存设置为0。这没错但是低效。事实上,如果涉及到值类型,是相当低效的。

  1. MyValType myVal1;  // initialized to 0
  2. MyValType myVal2 = new MyValType(); // also 0

Both statements initialize the variable to all 0s. The first does so by setting the memory containing MyVal1 to 0. The second uses the IL instruction initobj, which causes both a box and an unbox operation on the _MyVal2 variable. This takes quite a bit of extra time (see Item 17).

两条语句都将变量设置成全0。第一个,将含有myVal1的内存设置为0;第二个,使用了IL指令 init obj,这在myVal2上会同时引发装箱和拆箱,会花费相当多额外时间(Item 17)

The second inefficiency comes when you create multiple initializations for the same object. You should use the initializer syntax only for variables that receive the same initialization in all constructors. This version of MyClass has a path that creates two different ArrayList objects as part of its construction:

当你为同一个对象创建多个初始化时,会碰到第二个低效的做法。你应该仅仅为这种变量使用初始化器语法:从所有的构造函数上接收同样的初始化过程。这个版本的MyClass有一个路径,在构造函数的一部分创建了2个不同的ArrayList对象。

  1.     public class MyClass
  2.     {
  3.         // declare the collection, and initialize it.
  4.         private ArrayList coll = new ArrayList();
  5.         MyClass()
  6.         {
  7.         }
  8.         MyClass(Int32 size)
  9.         {
  10.             coll = new ArrayList(size);
  11.         }
  12.     }

When you create a new MyClass, specifying the size of the collection, you create two array lists. One is immediately garbage. The variable initializer executes before every constructor. The constructor body creates the second array list. The compiler creates this version of MyClass, which you would never code by hand. (For the proper way to handle this situation, see Item 14.)

当你创建一个新的MyClass时,指定集合的大小,就创建了2个数组列表。一个很快成为了垃圾。变量初始化器在每个构造函数前被执行,构造函数体创建了第二个数组列表。编译器为你创建了MyClass的这个版本,你可能从没有手工编写过(如何恰当的处理这种情况,请看Item 14)

  1.     public class MyClass
  2.     {
  3.         // declare the collection, and initialize it.
  4.         private ArrayList coll;
  5.         MyClass()
  6.         {
  7.             coll = new ArrayList();
  8.         }
  9.         MyClass(int size)
  10.         {
  11.             coll = new ArrayList();
  12.             coll = new ArrayList(size);
  13.         }
  14.     }

The final reason to move initialization into the body of a constructor is to facilitate exception handling. You cannot wrap the initializers in a Try block. Any exceptions that might be generated during the construction of your member variables get propagated outside of your object. You cannot attempt any recovery inside your class. You should move that initialization code into the body of your constructors so that you implement the proper recovery code to create your type and gracefully handle the exception (see Item 45).

将初始化移到构造函数体内部的最后一个原因是,便于处理异常。你不能将初始化器放到Try代码块里面。在你的成员变量给生成的期间,在对象外部可能发生任何异常。在类的内部你不能尝试任何修复。你应该将初始化代码移到构造函数内部,那样的话就可以实现合适的修复代码来创建你的类型,并且比较优雅的处理异常(Item 45)

Variable initializers are the simplest way to ensure that the member variables in your type are initialized regardless of which constructor is called. The initializers are executed before each constructor you make for your type. Using this syntax means that you cannot forget to add the proper initialization when you add new constructors for a future release. Use initializers when all constructors create the member variable the same way; it's simpler to read and easier to maintain.

在忽略哪个构造函数被调用的情况下,为了保证类型内部的成员变量都能被初始化,使用变量初始化器是最简单的方法。初始化器在每个构造函数之前被执行。使用该语法意味着,当你为了以后的发布版本添加新的构造函数的时候,不会忘记添加合适的初始化。在所有的构造函数使用同样的方式创建成员变量的时候,使用初始化器,更加易读,更加容易维护。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值