Welcome

首页 / 软件开发 / C# / Effective C#原则41:选择DataSet而不是自定义的数据结构

Effective C#原则41:选择DataSet而不是自定义的数据结构2010-12-13 博客园 Wu.Country@侠缘译因为两个原则,把DataSet的名声搞的不好。首先就是使用XML序列化的 DataSet与其它的非.Net代码进行交互时不方便。如果在Web服务的API中使用 DataSet时,在与其它没有使用.Net框架的系统进行交互时会相当困难。其次, 它是一个很一般的容器。你可以通过欺骗.Net框架里的一些安全类型来错误 DataSet。但在现代软件系统中,DataSet还可以解决很多常规的问题。如果你明 白它的优势,避免它的缺点,你就可以扩展这个类型了。

DataSet类设计 出来是为了离线使用一些存储在相关数据库里的数据。你已经知道它是用来存储 DataTable的,而DataTable就是一个与里的结构在行和列上进行匹配的内 存表。或许你已经看到过一些关于DataSet支持在内部的表中建立关系的例子。 甚至还有可能,你已经见过在DataSet里验证它所包含的数据,进行数据约束的 例子。

但不仅仅是这些,DataSet还支持AcceptChanges 和 RejectChanges 方法来进行事务处理,而且它们可以做为DiffGrams存储,也就 是包含曾经修改过的数据。多个DataSet还可以通过合并成为一个常规的存储库 。DataSet还支持视图,这就是说你可以通过标准的查询来检测数据里的部份内 容。而且视图是可以建立在多个表上的。

然而,有些人想开发自己的存 储结构,而不用DataSet。因DataSet是一个太一般的容器,这会在性能上有所损 失。一个DataSet并不是一个强类型的存储容器,其实存储在里面的对象是一个 字典。而且在里的表中的列也是字典。存储在里的元素都是以System.Object的 引用形式存在。这使得我们要这样写代码:

int val = ( int ) MyDataSet.Tables[ "table1" ].
Rows[ 0 ][ "total" ];

以C#强类型的观点来看,这样的结构是很 麻烦的。如果你错误使用table1 或者total的类型,你就会得到一个运行时错误 。访问里面的数据元素要进行强制转化。而这样的麻烦事情是与你访问里面的元 素的次数成正比的,与其这样,我们还真想要一个类型化的解决方法。那就让我 们来试着写一个DataSet吧,基于这一点,我们想要的是:

int val = MyDataSet.table1.Rows[ 0 ].total;

当你看明白了类型 化的DataSet内部的C#实现时,就会知道这是完美的。它封装了已经存在的 DataSet,而且在弱类型的访问基础上添加了强类型访问。你的用户还是可以用 弱类型API。但这并不是最好的。

与它同时存在的,我会告诉你我们放弃 了多少东西。我会告诉你DataSet类里面的一些功能是如何实现的,也就是在我 们自己创建的自定义集合中要使用的。你可能会觉得这很困难,或者你觉得我们 根本用上不同DataSet的所有功能,所以,代码并不会很长。OK,很好,我会写 很长的代码。

假设你要创建一个集合,用于存储地址。每一个独立的元 素必须支持数据绑定,所以你我创建一个具有下面公共属性的结构:

public struct AddressRecord
{
private string _street;
public string Street
{
get { return _street; }
set { _street = value; }
}
private string _city;
public string City
{
get { return _city; }
set { _city = value; }
}
private string _state;
public string State
{
get { return _state; }
set { _state = value; }
}
private string _zip;
public string Zip
{
get { return _zip; }
set { _zip = value; }
}
}

下面,你要创建这个集合。因为我们要类型安全的集合,所以我 们要从CollectionsBase派生:

public class AddressList : CollectionBase
{
}