改善C#程序的50种方法 条款8:确保0为值类型的有效状态

转载 2007年09月21日 11:31:00

.NET系统的默认初始化机制会将所有的对象设置为0[14]。对于值类型来讲,我们无法阻止其他程序员将其所有的成员都初始化为0[15]。因此,我们应该将0作为值类型的默认值。

枚举类型就是一种典型的情况。我们创建的枚举类型决不应该将0视为无效状态。我们知道,所有的枚举类型都继承自System.ValueType。默认的枚举值从0开始,但是我们可以更改这种默认行为。

public enum Planet

{

  // 显式赋值。

  // 否则将默认从0开始。

  Mercury = 1,

  Venus = 2,

  Earth = 3,

  Mars = 4,

  Jupiter = 5,

  Saturn = 6,

  Neptune = 7,

  Uranus = 8,

  Pluto = 9

}

Planet sphere = new Planet();

这里的sphere将为0,显然是一个无效的状态。 这样,那些要求“枚举值必须位于预定义集合中”的代码(通常都是这样的情况)就不能正常工作了。因此,当我们创建自己的枚举值时,要确保0为有效的状态。 如果我们使用位模式来定义枚举值,那么应该将0定义为“不包括所有其他属性的情况”。

根据目前的情况来看,我们应该强制用户显式初始化枚举值:

Planet sphere = Planet.Mars;

但这将使得这样的枚举类型很难作为值类型的成员:

public struct ObservationData

{

  Planet   _whichPlanet; // 看的是什么呢?

  Double  _magnitude; // 感觉亮度。

}

创建ObservationData对象将得到一个无效的Planet字段:

ObservationData d = new ObservationData();

新创 建的ObservationData对象的_magnitude将为0,这是合理的。但_whichPlanet却是无效的。我们需要让0成为有效的状 态。如果可能的话,我们最好将0作为默认的值。Planet枚举类型没有一个明显的默认值。当用户没有给出明确的选择时,我们随便设定一个Planet值 是没有意义的。如果碰到这种情况,我们可以将0作为一个未初始化值明确表示出来,这样可方便后续再对其更新:

public enum Planet

{

  None = 0,

  Mercury = 1,

  Venus = 2,

  Earth = 3,

  Mars = 4,

  Jupiter = 5,

  Saturn = 6,

  Neptune = 7,

  Uranus = 8,

  Pluto = 9

}

Planet sphere = new Planet();

现在sphere将包含一个None值。将这个未 初始化的默认值添加到Planet枚举中,会给ObservationData结构带来一些影响。新创建的ObservationData对象将包含一个 值为0的_magnitude和一个值为None的_whichPlanet。这时候,我们应该添加一个显式的构造器,来支持用户显式初始化类型所有的字 段:

public struct ObservationData

{

  Planet   _whichPlanet; // 看的是什么呢?

  Double  _magnitude; // 感觉亮度。

  ObservationData( Planet target,

    Double mag )

  {

    _whichPlanet = target;

    _magnitude = mag;

  }

}

但是,要记住ObservationData仍然有一个默认构造器。用户仍可以使用默认的构造器来创建“让系统初始化”的变量,我们无法禁止用户这么做。

在讨论其他值类型之前,我们需要再谈一下枚举类型作为位标记(flag)来应用时的一些特殊规则。使用Flags特性的枚举类型应该总是将None值设为0:

[Flags]

public enum Styles

{

  None = 0,

  Flat = 1,

  Sunken = 2,

  Raised = 4,

}

许多开发人员都在位标记枚举值上使用“按位AND”(bitwise AND)操作符。如果遇到0值,就会出现严重的问题。如果Flat值为0,那么下面的测试将永远为false:

if ( ( flag & Styles.Flat ) != 0 ) // 如果Flat == 0,将永远为false。

  DoFlatThings( );

如果使用Flags,我们要确保0为有效状态,且其意义为“不包括所有其他标记的情况”。

如果值类型中包含有引用类型,会出现另一种常见的初始化问题。包含字符串就是一种常见的情况:

public struct LogMessage

{

  private int _ErrLevel;

  private string _msg;

}

LogMessage MyMessage = new LogMessage( );

MyMessage 对象的_msg字段将为一个空引用。我们没有办法强制做其他的初始化,但是我们可以使用属性来将该问题限定在类型内部。我们可以创建一个属性来将_msg 值暴露给类型的所有客户,并在属性内部添加逻辑,使其返回一个“内容为空的字符串”,而非一个空引用:

public struct LogMessage

{

  private int _ErrLevel;

  private string _msg;

  public string Message

  {

    get

    {

      return (_msg != null ) ?

        _msg : string.Empty;

    }

    set

    {

      _msg = value;

    }

  }

}

我们应该在类型内部使用这样的属性。这样做可以将空引用检查集中在一个地方。当从我们的程序集中被调用时,Message的访问器方法几乎肯定会被内联。我们在获得高效代码的同时,也将错误降到了最低。

综上所述,系统会将值类型的所有实例初始化为0。我们没有办法阻止用户创建“字段全部为0”的值类型实例。如果可能的话,我们应该将“字段全部为0”作为类型的默认值。作为一种特殊情况,被用做位标记的枚举类型,应该确保0的意义为“不包括所有其他标记的情况”。

 

《Effective C#》条款8:确保0为值类型的有效状态

.NET系统的默认初始化机制会将所有的对象设置为0[14]。对于值类型来讲,我们无法阻止其他程序员将其所有的成员都初始化为0[15]。因此,我们应该将0作为值类型的默认值。 枚举类型就是一种典型...
  • f9db33t79p
  • f9db33t79p
  • 2017年05月13日 19:18
  • 27

改善C#编程的50个建议(1-5)

翻译自Effective C# 1、属性(properties) 抽象属性可以放在接口的定义里。如: public interface INameValuePair     {         s...
  • edcvf3
  • edcvf3
  • 2014年03月19日 00:14
  • 1524

改善C#程序的50种方法

为什么程序已经可以正常工作了,我们还要改变它们呢?答案就是我们可以让它们变得更好。我们常常会改变所使用的工具或者语言,因为新的工具或者语言更富生产力。如果固守旧有的习惯,我们将得不到期望的结果。对于C...
  • u012076858
  • u012076858
  • 2014年09月16日 11:17
  • 270

C# 改善程序的50种方法

本文转载连接: http://blog.csdn.net/hr541659660/article/details/51556563?locationNum=12&fps=1 目录(?)[+]...
  • newbie_xymt
  • newbie_xymt
  • 2017年06月05日 14:32
  • 399

改善C#程序的50种方法

为什么程序已经可以正常工作了,我们还要改变它们呢?答案就是我们可以让它们变得更好。我们常常会改变所使用的工具或者语言,因为新的工具或者语言更富生产力。如果固守旧有的习惯,我们将得不到期望的结果。对于C...
  • hr541659660
  • hr541659660
  • 2016年06月01日 15:46
  • 4457

改善C#程序的50种方法

http://download.csdn.net/download/lc123scf/5267247 为什么程序已经可以正常工作了,我们还要改变它们呢?答案就是我们可以让它们变得更好。我们常...
  • zmq5411
  • zmq5411
  • 2016年04月02日 18:37
  • 909

改善C#程序的50种方法

原文:点击打开链接 为什么程序已经可以正常工作了,我们还要改变它们呢?答案就是我们可以让它们变得更好。我们常常会改变所使用的工具或者语言,因为新的工具或者语言更富生产力。如果固守旧有的习惯,我们将得...
  • yenange
  • yenange
  • 2013年08月06日 22:18
  • 6725

改善C#程序的50种方法卵

http://www.ichacha.net/%e5%a4%a7%e5%ba%86%e5%93%aa%e9%87%8c%e6%9c%89%e5%8d%96%e5%86%b0%e6%af%92%e7%9...
  • gong0810
  • gong0810
  • 2014年07月09日 13:47
  • 94

Effective C# Item8:确保0是值类型的有效状态

.NET会将对象的值默认设置为0,对于值类型来说,例如struct,我们无法阻止开发人员将结构体中的成员设置为0,因此,我们需要将0设置为有效状态。     对于枚举类型来说,如果通过new的方式新...
  • yin554393109
  • yin554393109
  • 2014年07月24日 10:57
  • 284

《Effective C#中文版:改善C#程序的50种方法》读书笔记

一、用属性代替可访问的字段   1、.NET数据绑定只支持数据绑定,使用属性可以获得数据绑定的好处;   2、在属性的get和set访问器重可使用lock添加多线程的支持。   二、readon...
  • walkerxian
  • walkerxian
  • 2014年09月13日 23:47
  • 361
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:改善C#程序的50种方法 条款8:确保0为值类型的有效状态
举报原因:
原因补充:

(最多只允许输入30个字)