常量错误

    枚举类型无疑给我们开发带来了很大的便利,智能感应+代码可读性就让我们有足够的理由在项目中使用。但枚举类型使用不当也存在着温柔陷阱,而且陷阱很难发现。

      事情的缘起是这样的,项目A是公共基类,很多项目都会引用,项目B会引用项目A,但由于项目B使用人数不多而且功能很稳定,所以部署的时候一般不会传项目B的dll文件。但前前几天项目B突然出错了,报错的“找不到业务类型对应的数据库连接”。本地调试项目B,一点问题没有,可线上的就是出错,重新上传了项目B的dll,神奇般的好了。感觉有些莫名奇妙,一点都没改动,重新上传下dll就好了,是什么原因呢?没有无缘无故的爱,同样也没有无缘无故的错误,《温柔的枚举陷阱》一文帮我找到了答案,问题的根源是项目A中枚举类型的更改。

      我们可以从下面的示例中找到答案。ProjectA是很多项目共用的基础类库,ProjectB会添加ProjectA的引用,但二者并不在一个解决方案下面,更新ProjectA时会把A的dll文件放到B的bin目录下面。

项目ProjectA的代码示例
   
   
namespace ProjectA
{
/// <summary>

/// 业务类型
/// </summary>

public enum BusinessType
{
UserRead,
UserWrite,
ProductRead,
ProductWrite
}

public class
DBHelper
{
/// <summary>

/// 根据业务类型获取连接字符串
/// </summary>

public static string GetConnectString(BusinessType bt)
{
string connectString = string
.Empty;
switch
(bt)
{
case
BusinessType.UserRead:
connectString
= "UserRead"
;
break
;
case
BusinessType.UserWrite:
connectString
= "UserWrite"
;
break
;
case
BusinessType.ProductRead:
connectString
= "ProductRead"
;
break
;
case
BusinessType.ProductWrite:
connectString
= "ProductWrite"
;
break
;
default
:
connectString
= "UserRead"
;
break
;
}
return
connectString;
}
}
}

      项目B添加对项目A的引用后,其代码如下。

项目ProjectB代码示例
   
   
using ProjectA;

namespace
ProjrctB
{
public class
B
{
public static void
GetUser(BusinessType bt)
{
//根据BusinessType选择合适的数据库获取数据

string connectString = DBHelper.GetConnectString(bt);
Console.WriteLine(connectString);
}
}
}

       执行ProjrctB.B.GetUser(BusinessType.ProductRead)后毫无疑问输出“ProductRead”,和我们预期的一致。接下来业务类型扩展了,要在BusinessType中增加评论类型,修改后的代码如下。

项目ProjectA业务类型扩展后的代码示例
   
   
namespace ProjectA
{
/// <summary>

/// 业务类型
/// </summary>

public enum BusinessType
{
CommentRead,
CommentWrite,
UserRead,
UserWrite,
ProductRead,
ProductWrite
}

public class
DBHelper
{
/// <summary>

/// 根据业务类型获取连接字符串
/// </summary>

public static string GetConnectString(BusinessType bt)
{
string connectString = string
.Empty;
switch
(bt)
{
case
BusinessType.CommentRead:
connectString
= "CommentRead"
;
break
;
case
BusinessType.CommentWrite:
connectString
= "CommentWrite"
;
break
;
case
BusinessType.UserRead:
connectString
= "UserRead"
;
break
;
case
BusinessType.UserWrite:
connectString
= "UserWrite"
;
break
;
case
BusinessType.ProductRead:
connectString
= "ProductRead"
;
break
;
case
BusinessType.ProductWrite:
connectString
= "ProductWrite"
;
break
;
default
:
connectString
= "UserRead"
;
break
;
}
return
connectString;
}
}
}

       重新生成ProjectA,将其dll部署到ProjectB的bin目录下面,这时候执行ProjrctB.B.GetUser(BusinessType.ProductRead)还会得到我们期待的结果吗?答案是否定的,执行后得到的结果是“UserRead”,并不是我们想要的“ProductRead”类型。为什么会出现这种情况呢?

       枚举值本质上就是个整数值,代码编译后,dll中只保留该枚举的整数值,而不会保留枚举变量名。如果枚举本身发生变化,如示例中在枚举BusinessType前面插入了两项,那么后面枚举变量的值都会改变的(如果不是显示指定值的话)。这个时候如果只重新编译了枚举本身,而没有编译引用枚举的地方ProjectB,那么就会出现张冠李戴的问题,因为整数值代表的枚举类型已经变了。这个问题解决的办法是创建枚举时显示指定枚举变量的值,扩展修改枚举类型时不要改变枚举变量的值。如下面的代码,添加业务类型时,将CommentRead = 4和CommentWrite = 5加入即可,而不要动以前的业务类型UserRead = 0,这样扩展类型时及时不去重新编译ProjectB,也不会出现上述问题了。

显示指定枚举变量的值
   
   
/// <summary>
/// 业务类型
/// </summary>

public enum BusinessType
{
CommentRead
= 4
,
CommentWrite
= 5
,
UserRead
= 0
,
UserWrite
= 1
,
ProductRead
= 2
,
ProductWrite
= 3

}

        问题的本质在于编译时直接用变量的值代替了变量的名称,不仅枚举类型存在这个问题,常量同样也存在该问题,如果更新了常量的值,而没用编译引用到常量的项目,那么常量值的修改对引用到它的项目来说是无效的,因此有人建议除了值固定不变的常量(如圆周率),可以用readonly代替常量。

        如果不是看到类似问题的文章,这种问题很难找到答案,写出来对自己是一种提高,也希望能给遇到类似问题的朋友一些帮助。

 

http://www.cnblogs.com/freshman0216/archive/2010/07/18/1780023.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值