数据一致性

定义如下Address结构体:

public struct Address
{
    private string province;
    private string city;
    private string zip;

    public string Province
    {
        get { return province; }
        set { province = value; }
    }

    public string City
    {
        get { return city; }
        set { city = value; }
    }

    public string Zip
    {
        get { return zip; }
        set
        {
            CheckZip(value); // 验证格式
            zip = value;
        }
    }

    private void CheckZip(string value)
    {
        string pattern = @"\d{6}";
        if (!Regex.IsMatch(value, pattern))
        {
            throw new Exception("Zip is invalid!");
        }
    }
}

接下来使用刚刚创建的结构体

try
{
    Address a = new Address();

    a.Province = "陕西";
    a.City = "西安";
    a.Zip = "710068";

    a.City = "青岛";
    a.Zip = "12345";
    a.Province = "山东";
}
catch
{
}

结果出现了数据不一致的问题,当给Zip赋值的时候,因为发生了异常,所以出现了Province是陕西,City却是青岛这种情况。另外,在多线程下,也会出现类似的情况。那么如何改进呢?先来看一下类型可以具有的两个特性:原子性和常量性。

对象的原子性:对象的状态是一个整体,如果一个字段改变,其他字段也要同时作出相应改变。简单来说,就是要么不改,要改全改。

对象的常量性:对象的状态一旦确定,就不能再次更改了。如果想再次更改,需要重新构造一个对象。

对于原子性,实施的办法是添加一个构造函数,在这个构造函数中为对象的所有字段赋值。为了实施常量性,将属性中的set访问器删除,同时将字段声明为readonly。

 

上面的方法解决了数据不一致的问题,但还漏掉一点:当类型内部维护着一个引用类型的字段时,比如数组,尽管将它声明为readonly,在类型外部还是可以对它进行修改。现在我们修改Address 类,添加一个数组phones,存储电话号码:

private readonly string[] phones;

public Address(string province, string city, string zip, string[] phones) {   
    // 略...
    this.phones = phones;
}

public string[] Phones {
    get { return phones; }
}

我们接下来做个测试:

string[] phones = { "029-88401100", "029-88500321" };
Address a = new Address("陕西", "西安", "710068", phones);

Console.WriteLine(a.Phones[0]);     // 输出: 029-88401100

string[] b = a.Phones;
b[0] = "029-XXXXXXXX";       // 通过b修改了 Address的内容

Console.WriteLine(a.Phones[0]); // 输出: 029-XXXXXXXX

为了解决这个问题,可以在构造函数中对外部传递进来的数组进行深度复制:

public Address(string province, string city, string zip, string[] phones)
{        
    // 前面略...
    this.phones = new string[phones.Length];
    phones.CopyTo(this.phones, 0);
    CheckZip(zip);    // 验证格式
}
posted @ 2014-04-21 11:44  LieuJoey  阅读(196)  评论(0编辑  收藏  举报