深入了解ASP.NET中的“空”
空对于许多开发人员真是很虚无缥缈,难以捉摸的一个概念。
何为空
按照字面意思,通俗的理解就是空洞无物,没有任何东西。然而与程序开发中,由此延伸的概念却是非常丰富的。
l 从Web开发的展现页面来看,如果本可以有页面呈现的对象,却没有内容呈现在浏览器中,可以称之为“空”。从技术角度看,就是没有标签属性值或纯文本内容,或二进制数据从服务器端响应。在Web页面的可输入区域,如果没有输入任何内容,这也是“空”,在Server端接收这些可输入区数据时,都首先被作为System.String类型,然后会隐式或显式的转换为其他类型。
浏览器直接处理的数据包括,HTML标签,纯文本,二进制流,脚本。HTML语法是无类型的描述性语言。可见浏览器处理的数据就可分为文本和二进制数据。
l 从.NET托管代码的角度来看,“空”可有以下多种情况:
1. Nothing(VB.NET中是Nothing,C#中等价的为NULL)
首先要明确Nothing是个引用类型,其用途是释放一个引用类型变量对引用类型实例的引用。简单的说就是让原本指向一个引用类型实例的变量重新归于未初始化,把他存储的引用类型实例的存储地址释放掉。注意:只要执行指针没有跳出这个变量的生存范围,这个变量就依然存在于内存中。(如果一个引用类型实例,已经没有变量指向他,那么他会被垃圾回收器立即回收销毁。注意:GC有效管理的通常是托管资源,但要明确的是,非托管资源最终也还是要由GC来销毁。.NET Framework 提供 Object.Finalize 方法,GC通在销毁托管及非托管对象之前,都会自动调用一下这个方法,这是个可重写的方法,目的是在此方法中可以撰写在对象被销毁前进行必要的清理工作。 Finalize方法只能由GC自动调用,而不能撰写代码显式调用,所以调用的时间就不确定,对于急需释放清理的资源,.NET Framework又给出了Idispose接口,此接口定义了可以显式调用的Dispose()方法,使得我们可以控制何时释放不再使用的资源,释放以后再交给GC去处理。 Finalize方法与Idispose接口是基于同样目的,互不包含,可选其一使用的资源释放方式。
GC对于非托管资源,例如文件、窗口或网络连接。虽然可以跟踪他们的生存期,但它不了解具体如何清理这些资源。所以需要使用自定义逻辑来辅助GC)
2. String.Empty与托管值类型的空值
还是从托管代码的角度来看,如果一个String类型的变量赋值为””或等价的String.Empty。或一个值变量定义以后没有赋值。 以上这些也可以空的另一种情况,即值为“空”
注意:因为String是引用类型,所以值为空时,也是需要赋值为””或String.Empty,才能初始化。
3. DBNull
SQL数据表中,数据库中的空 (特别注意:在SQL的数据类型中,文本类型的值为空和NET语言一样都,也是有两种情况,即有空值和什么都没有) ,在SQL语法中,对应SQL的Null对象。NET Framework中为了与这个SQL的Null类型对应,专门创建了System.DBNull类型。DBNull.value就对应SQL数据表字段的空。
如果NET托管代码中把一个DBNull.value赋值给SQL数据表中不能为空的字段,就会引发异常;如果从数据表某字段读出空(在托管代码中自动对应为DBNull.value值),把它赋值给一个TextBox对象Text属性,同样会抛出异常。
为了解决以上会发生异常的状况,ASP.NET中为不同的情景提供了不同的处理方式:
写入数据库时,如果赋值给SQL操作参数的托管值类型变量为空,或String类型为String.Empty时,可以把这些空值转换为DBNull
从数据库读取数据时,如果读出的是DBNull.value,可以转换为String.Empty或值类型的空值。
Net Framework的服务器控件中,数据源控件,数据呈现空间,通常都有涉及以上两种情况处理的相关属性。
例如,GridView、FormView和DetailsView都支持EmptyDataText或EmptyDataTemplate属性,当数据源没有返回数据行的时候,你可以使用这些属性来指定控件显示的内容。我们只需要设置EmptyDataText和EmptyDataTemplate其中的一个(如果两个都设置了,EmptyDataTemplate会被重载)。
对于数据呈现控件的绑定字段(和衍生的字段类型)、模板字段或数据源参数对象上指定ConvertEmptyStringToNull属性,指明在向数据库写入数据之前,来自客户端的String.Empty值将被转换为DBNull.value。
绑定字段(和衍生的字段类型)的NullDisplayText属性,当数据源返回的某个字段的值为空的时候,它指定显示的内容。如果在编辑模式中这个值没有发生变化,那么在更新操作中这个值会以空值的形式返回给数据源,而不是NullDisplayText设置的文本。
ObjectDataSource也支持ConvertNullToDbNull属性,当相关的方法要求用DbNull代替空值(DataSet的TableAdapter类就有这个要求)的时候,我们就可以把这个属性设置为真。
数据源SQL命令参数的DefaultValue属性,如果ConvertEmptyStringToNull和DefaultValue都被设置了,那么String.Empty值会首先被转换为DBNull.value,接着被赋予默认值。