最近研究了一下C#2.0中的可空类型发现一些有趣的事实,请看代码
则下面的逻辑表达式结果如何?
奇怪吗?
第一个逻辑表达式为true是意料之中的,而第二个表达式为false就有些意料之外了,但仔细想一下,就会感觉有它存在的道理。我们都知道int?就是Nullable<int>的缩写,而在.Net Framework中Nullable<T>实现其实是一个继承自值类型的结构,只是这个结构多了个属性HasValue,用来标识结构中是否有值,这样再理解上面的结果就不奇怪了,因为语句object b = a;会有一个装箱操作,也就是b中的引址为指向装箱后的a结构,而不是空引用,因此就会有上面的结果了。
这点只是C#语言中的一些小细节,但在很多时候可能会引起些不可以预料的事果,比如微软发布的DataAccessBlock中用来把存储过程的参数数组的时候SqlHelper中的代码
在某些情况下将不在有效,因为p.Value为空的判断p.Value==null在p.Value中存贮可空类型的时候可能会失效(如果p.Value中存贮的对象是可空类型,而它的值刚好为空时p.Value == null会返回false但在这种情况下我们仍应该将p.Value赋值为DBNull.Value),这时会导致运行对象没有实现IConvertable的出错信息。 改后代码如下:
总的来讲可空类型为我们提供了很大的方便,特别是在对数据库的可空字段的操作提供了方便,但使用时应注意上面的情况才能作到万无一失。
int? a = null;
object b = a;
object b = a;
a==null //true
b==null //false
b==null //false
第一个逻辑表达式为true是意料之中的,而第二个表达式为false就有些意料之外了,但仔细想一下,就会感觉有它存在的道理。我们都知道int?就是Nullable<int>的缩写,而在.Net Framework中Nullable<T>实现其实是一个继承自值类型的结构,只是这个结构多了个属性HasValue,用来标识结构中是否有值,这样再理解上面的结果就不奇怪了,因为语句object b = a;会有一个装箱操作,也就是b中的引址为指向装箱后的a结构,而不是空引用,因此就会有上面的结果了。
这点只是C#语言中的一些小细节,但在很多时候可能会引起些不可以预料的事果,比如微软发布的DataAccessBlock中用来把存储过程的参数数组的时候SqlHelper中的代码
private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
if (command == null) throw new ArgumentNullException("command");
if (commandParameters != null)
{
foreach (SqlParameter p in commandParameters)
{
if (p != null)
{
if ((p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input) &&
(p.Value == null))
{
p.Value = DBNull.Value;
}
command.Parameters.Add(p);
}
}
}
}
{
if (command == null) throw new ArgumentNullException("command");
if (commandParameters != null)
{
foreach (SqlParameter p in commandParameters)
{
if (p != null)
{
if ((p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input) &&
(p.Value == null))
{
p.Value = DBNull.Value;
}
command.Parameters.Add(p);
}
}
}
}
private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
if (command == null) throw new ArgumentNullException("command");
if (commandParameters != null)
{
foreach (SqlParameter p in commandParameters)
{
if (p != null)
{
if (p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input)
{
if (p.Value != null)
{
Type typeInf = p.Value.GetType();
if (typeInf.Name == "Nullable`1" &&
(bool)typeInf.GetProperty("HasValue").GetValue(p.Value, null) == false)
{
p.Value = DBNull.Value;
}
}
else
{
p.Value = DBNull.Value;
}
}
command.Parameters.Add(p);
}
}
}
}
{
if (command == null) throw new ArgumentNullException("command");
if (commandParameters != null)
{
foreach (SqlParameter p in commandParameters)
{
if (p != null)
{
if (p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input)
{
if (p.Value != null)
{
Type typeInf = p.Value.GetType();
if (typeInf.Name == "Nullable`1" &&
(bool)typeInf.GetProperty("HasValue").GetValue(p.Value, null) == false)
{
p.Value = DBNull.Value;
}
}
else
{
p.Value = DBNull.Value;
}
}
command.Parameters.Add(p);
}
}
}
}
总的来讲可空类型为我们提供了很大的方便,特别是在对数据库的可空字段的操作提供了方便,但使用时应注意上面的情况才能作到万无一失。