提高C#编程水平的50个要点 之八“在值类型中,确保0是一个合法的数据”

.Net系统默认所有的对象初始化时都为0。这并没有提供一个方法来预防其他程序员创建的值类型数据的实例在初始化是都是0。

请让你的数据类型默认值也是0。

一个特殊情况是在枚举类型数据中。决不要创建一个不包括0在内 的枚举类型。所有的枚举类型都是从System.ValueType派生的。枚举类型的值是 从0开始的,但你可以改变这一行为:

public enum Planet
{
 // Explicitly assign values.
 // Default starts at 0 otherwise.
 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是当中的一个。如果 你的枚举类型采用的是以位(bit)模式,把0定义为其它属性不存在时的取值。

按照现在的情况,你迫使用户必须精确的初始化值:

Planet sphere = Planet.Mars;

这将使包含 (Planet)这一类型的其它类型很难创建:

public struct ObservationData
{
 Planet  _whichPlanet; //what am I looking at?
 Double _magnitude; // perceived brightness.
}

创建一个新ObservationData实例的用户会创建一个不合法的 Planet成员:

ObservationData d = new ObservationData ();

最后创建的ObservationData的成员_magnitude的值是0,这 是合理的。但_whichPlanet却是无效的。你须要让0也是有效的(状态)。如果可 能,选择把0做为一个最好的默认。Planet枚举类型没有一个明确的默认值,无 论用户是否任意的选择一些行星,5自学网,这都不会给人留下好的感觉。当你陷入这样的 情况时,使用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对象的目标上具有None和一个数值0。添加一个清晰的构造函数 让用户为你的类型的所有字段明白的初始化:

public struct ObservationData
{
 Planet  _whichPlanet; //what am I looking at?
 Double _magnitude; // perceived brightness.
 ObservationData( Planet target,
  Double mag )
 {
  _whichPlanet = target;
  _magnitude = mag;
 }
}

但请记住,默认的构造函数还是可访问的,而且是结构的部份。 用户还是可以创建一个系统初始化的变量,而你无法阻止它。

在结束枚 举类型转而讨论其它类型之前,你须要明白几个用于标记的特殊枚举类型规则。 枚举类型在使用Flags特性时,必须把None的值设置为0:

[Flags]
public enum Styles
{
 None = 0,
 Flat = 1,
 Sunken = 2,
 Raised = 4,
}

很多开发 人员使用枚举标记和位运算操作AND进行运行,5自学网,0值会与位标记产生严重的问题。 下面这个实验如果Flat的值是0时,是决不会成功的:

if ( ( flag & Styles.Flat ) != 0 ) // Never true if Flat == 0.
  DoFlatThings( );

如果你遇到Flags,确保0对它来说是有效的, 并且这就着:“对所有缺少的标记。”

另一个很常见的初始 化问题就是值类型中包含了引用类型。字符串是一个常见的例子:

public struct LogMessage
{
 private int _ErrLevel;
 private string _msg;
}
LogMessage MyMessage = new LogMessage( );

MyMessage包含了一个_msg为 null的引用字段。这里没有办法强行使用另一个不同的初始化方法,但你利用属 性来局部化这个问题。你创建一个属性向所用的用户暴露_Msg的值。添加一个业 务逻辑,使得当字符串为null引用是,用空 串来取而代之:

public struct LogMessage
{
 private int _ErrLevel;
 private string _msg;
 public string Message
 {
  get
  {
   return (_msg != null ) ?
    _msg : string.Empty;
  }
  set
  {
   _msg = value;
  }
 }
}


在你自己的 数据类型内部,你应该添加这样的一个属性。做了这样的局部处理后,null引用 在某一位置做了验证。当调用是在你的程序集内时,Message的访问器基本上是 可以很好的内联的。你将会取得高效低错的代码。

系统为所有的值类型 数据初始化为0,而没有办法防止用户在创建一个值类型实例时,给所有的值类 型都赋值为0。如果可能,把0设置为自然的默认值。特殊情况下,使用Flags特性的枚举类型必须确保0是所有缺省标记的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值