您的位置:首页 > Web前端

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

2008-10-09 20:21 302 查看
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#里面是很自然的事情,仅仅就是赋一个值: public class MyClass
{
// declare the collection, and initialize it.
private ArrayList coll = new ArrayList();
}

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。这没错但是低效。事实上,如果涉及到值类型,是相当低效的。MyValType myVal1; // initialized to 0
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对象。 public class MyClass
{
// declare the collection, and initialize it.
private ArrayList coll = new ArrayList();
MyClass()
{
}

MyClass(Int32 size)
{
coll = new ArrayList(size);
}
}

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)。 public class MyClass
{
// declare the collection, and initialize it.
private ArrayList coll;
MyClass()
{
coll = new ArrayList();
}

MyClass(int size)
{
coll = new ArrayList();
coll = new ArrayList(size);
}
}

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.

在忽略哪个构造函数被调用的情况下,为了保证类型内部的成员变量都能被初始化,使用变量初始化器是最简单的方法。初始化器在每个构造函数之前被执行。使用该语法意味着,当你为了以后的发布版本添加新的构造函数的时候,不会忘记添加合适的初始化。在所有的构造函数使用同样的方式创建成员变量的时候,使用初始化器,更加易读,更加容易维护。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: