Effective C# 原则12:选择变量初始化而不是赋值语句
Item 12: Prefer Variable Initializers to Assignment Statements

(译注:根据我个人对文章的理解,我把initializer译为:初始化器,它是指初始化语法,也就是在一个类里声明变量的同时,直接创建实例值的方法。
例:object m_o = new object();如果这段代码不在任何函数内,但在一个类里,它就是一个初始化器,而不管你是把它放在类的开始还以结尾。)

一些类经常不只一个构造函数。时间一长,就难得让它的成员变量以及构造函数进行同步了。最好的确保这样的事不会发生的方法就是:在声明就是的时间就直接初始化,而不是在每个构造函数内进行赋值。而且你应该使用初始化器语法同时为静态的和实例的变量进行初始化。

在C#里,当你声明一个变量时就自然的构造了这个成员变量。直接赋值:
public class MyClass
{
  // declare the collection, and initialize it.
  private ArrayList _coll = new ArrayList( );
}

忽略你最终会给MyClass添加多少个构造函数,_coll会正确的初始化。编译器会产生一些代码,使得在你的任何一个构造函数调用前,都会初始化你声明的实例变量。当你添加一个新的构造函数时,_coll就给你初始化了。当你添加了一个新的变量,你不用在所有的构造函数里添加初始化代码;直接在声明的地方对它进行初始化就行了。同样重要的是:如果你没有明确的声明任何一个构造函数,编译会默认的给你添加一个,并且把所有的变量初始化过程都添加到这个构造函数里。

初始化器更像是一个到构造函数的方便的快捷方法。初始化生成的代码会放置在类型的构造函数之前。初始化会在执行类型的基类的构造函数之前被执行,并且它们是按你声明的先后关系顺序执行的。

使用初始化器是一个最简单的方法,在你的类型里来避免使用一些没有赋值的变量,但这并不是很好。下面三种情况下,你不应该使用初始化器语法。首先就是,如果你是初始化一个对象为0,或者为null。系统默认会在你任何代码执行前,为所有的内容都初始化为0。系统置0的初始化是基于底层的CPU指令,对整个内存块设置。你的任何其它置0的初始化语句是多余的。C#编译器忠实的添加额外的指令把内存设置为0。这并没有错,只是效率不高。事实上,如果是处理值类型数据,这是很不值的:

MyValType _MyVal1;  // initialized to 0
MyValType _MyVal2 = new MyValType(); // also 0

两条语句都是把变量置为0。第一个是通过设置包含_MyVal1的内存来置0;而第二个是通过IL指令initobj,这对变量_MyVal2会产生装箱与拆箱操作。这很要花一点额外的时间(参见原则17)。

第二个低效率的是在你为一个对象添加两个构造函数时会产生。你使用初始化器初始化变量,而所有的构造函数也对这些变量进行了初始化。这个版本的MyClass两个不同的ArrayList对象在它的构造函数内:

public class MyClass
{
  // declare the collection, and initialize it.
  private ArrayList _coll = new ArrayList( );

MyClass( )
  {
  }

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

当你创建一个新的MyClass对象时,特别指定集合的大小,你创建了两个数组列表。其中一个很快成为垃圾对象。初始化器在所有的构造函数之前会执行,构造函数会创建第2个数组列表。编译器产生了这个的一个版本,当然这是你决不会手动写出来的。(参见原则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 );
  }
}

最后一个原因要把初始化放到构造函数里就是促使异常的捕获。你不能在初始化器中使用try块,任何在构造时因成员变量产生的异常可能衍生到对象的外面。你无法试图在你的类里来捕获它。你应该把那些初始化代码移到构造函数里,这样你就可以捕获异常从而保证你的代码很友好(参见原则45)。

变量初始化器是一个最简单的方法,在忽略构造函数时来保证成员变量被正确的初始化。初始化器在所有的构造函数之前被执行。使用这样的语法意味着当你在为后来发布的版本中添加了构造函数时,不会忘记添加恰当的初始化到构造函数里。当构造函数与初始化生成同样的成员对象时,就使用初始化器。阅读简单而且易于维护。

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:

public class MyClass
{
  // declare the collection, and initialize it.
  private ArrayList _coll = new ArrayList( );
}

Regardless of the number of constructors you eventually addto 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.

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 wrongit'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

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).

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:

public class MyClass
{
  // declare the collection, and initialize it.
  private ArrayList _coll = new ArrayList( );

MyClass( )
  {
  }

MyClass( int 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.)

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).

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.

转载于:https://www.cnblogs.com/WuCountry/archive/2007/03/01/660646.html

Effective C# 原则12:选择变量初始化而不是赋值语句相关推荐

  1. [转]Effective C# 原则7: 选择恒定的原子值类型数据

    恒定类型(immutable types)其实很简单,就是一但它们被创建,它们(的值)就是固定的.如果你验证一些准备用于创建一个对象的参数,从前面的观点上看, 你知道它在合法(valid)状态.你不能 ...

  2. Effective C# 原则35:选择重写函数而不是使用事件句柄(译)

    Effective C# 原则35:选择重写函数而不是使用事件句柄 Item 35: Prefer Overrides to Event Handlers 很多.Net类提供了两种不同的方法来控制一些 ...

  3. Effective C# 原则11:选择foreach循环

    Effective C# 原则11:选择foreach循环 Item 11: Prefer foreach Loops C#的foreach语句是从do,while,或者for循环语句变化而来的,它相 ...

  4. Effective C# 原则13:用静态构造函数初始化类的静态成员(译)

    Effective C# 原则13:用静态构造函数初始化类的静态成员 Item 13: Initialize Static Class Members with Static Constructors ...

  5. Effective C# 原则1:尽可能的使用属性(property),而不是数据成员(field)。

    Effective C# 原则1:尽可能的使用属性(property),而不是数据成员(field).<?xml:namespace prefix = o ns = "urn:sche ...

  6. Effective C# 原则8:确保0对于值类型数据是有效的(翻译)

    Effective C# 原则8:确保0对于值类型数据是有效的 Ensure That 0 Is a Valid State for Value Types .Net系统默认所有的对象初始化时都为0. ...

  7. Effective C# 原则18:实现标准的处理(Dispose)模式(译)

    Effective C# 原则18:实现标准的处理(Dispose)模式 我们已经讨论过,处理一个占用了非托管资源对象是很重要的.现在是时候来讨论如何写代码来管理这些类占用的非内存资源了.一个标准的模 ...

  8. Effective C# 原则16:垃圾最小化(译)

    Effective C# 原则16:垃圾最小化 Item 16: Minimize Garbage 垃圾回收器对内存管理表现的非常出色,并且它以非常高效的方法移除不再使用的对象.但不管你怎样看它,申请 ...

  9. 读书笔记_代码大全2第十章_变量初始化

    变量初始化原则 声明变量的同时初始化. 在靠近变量第一次使用的位置初始化(就近原则). 最好在靠近变量第一次使用的位置声明和定义变量. 在可能的情况下使用final或const(可以防止变量在初始化之 ...

  10. Effective C# 原则34:创建大容量的Web API(译)

    Effective C# 原则34:创建大容量的Web API Item 34: Create Large-Grain Web APIs 交互协议的开销与麻烦就是对数据媒体的如何使用.在交互过程中可能 ...

最新文章

  1. 八皇后算法python_Python学习二(生成器和八皇后算法)
  2. [Cocoa]深入浅出Cocoa之Core Data(4)- 使用绑定
  3. 换个姿势学设计模式:策略模式
  4. C++的clone函数什么时候需要重载
  5. ptmalloc内存分配释放
  6. 数据结构压缩_将数据压缩到数据结构中
  7. mysql存储过程触发器游标_MySQL存储过程,触发器,游标
  8. Html前端基础(form表单、img标签、a href标签、id的作用)
  9. 在Flex中获取一个屏幕截图(Screenshot)并将其传递给ASP.NET
  10. flex自定义preloader预加载进度条
  11. 大数据分析平台的作用有什么
  12. 情绪管理--不要总做“好脾气”的人。
  13. C语言函数嵌套调用作业总结
  14. 虚拟机xftp工具连接服务器,xftp5(ftp上传工具)如何连接虚拟机?
  15. 华硕fl5600l重装系统
  16. 手机端网页尺寸html,手机端网页设计尺寸_html/css_WEB-ITnose
  17. L9110电机驱动电路
  18. 在宜家兼职收银员创收
  19. MySQL 10060错误 解决方法
  20. SpringMVC从入门到精通(终结版)

热门文章

  1. 通用预处理器宏assert()的用法
  2. java trimprefix_MyBatis动态SQL中的trim标签的使用方法
  3. 古代埃及希腊,数学用的什么进制
  4. 六石管理学:个人机器的开发环境也有硬性要求
  5. JAVA使用反射的方法,参数是数组怎么办?
  6. bash: dh_make:未找到命令
  7. sprintf()出错,使用strcat()正确
  8. 某人说自己是佛菩萨转世,什么情况下才可信
  9. 关于引力波的一些疑问
  10. UNBUNTU下与VirtualBox的WINDOWS共享文件夹