泛型结构

与类相似,结构也可以是泛型的。它们非常类似于泛型类,只是没有继承特性。

 

.NET Framework中 的一个泛型结构是 Nullable<T>。数据库中的数字和编程语言中的数字有显著不同的特征,因为数据库中的数字可以为空,而 C# 中的数字不能为空。Int32 是一个结构,而结构的实现同值类型,所以结构不能为空。这个问题不仅存在于在数据库中,也存在于把 XML 数据映射到,NET类型。

 

这种区别常常令人很头痛,映射数据也要多做许多辅助工作。一种解决方案是把数据库和XML文件中的数字映射为引用类型,因为引用类型可以为空值。但这也会在运行期间带来额外的系统开销。

 

使用 Nullable<T> 结构很容易解决这个问题。下面的代码段说明了如何定义 Nullable<T> 的一个简化版本。

 

结构 Nullable<T> 定义了一个约束:其中的泛型类型 必须是一个结构。把类定义为泛型类型后,就没有低系统开销这个优点了,而且因为类的对象可以为空,所以对类使用 Nullable<T> 型是没有意义的。除了 Nullable<T> 定义的T类型之外,唯一的系统开销是 hasValue 布尔字段,它确定是设置对应的值,还是使之为空。除此之外,泛型结构还定义了只读属性 HasValue 和 value,以及一些操作符重载。 把 Nullable<T> 类型强制转换为T类型的操作符重载是显式定义的,因为当 hasValuefalse,它会抛出一个异常。强制转换为 Nullable<T> 类型的操作符重载定义为隐式的,因为它总是能成功地转换:

public class Nullable<T> where T:struct
{
    private bool hasValue;

    public bool HasValue
    {
        get { return hasValue; }
        set { hasValue = value; }
    }

    private T value;

    public T Value
    {
        get 
        {
            if (!hasValue)
            {
                throw new InvalidOperationException("no value");
            }
            return value;
        }
    }


    public Nullable(T value)
    {
        this.hasValue = true;
        this.value = value;
    }

    public static explicit operator T(Nullable<T> value)
    {
        return value.Value;
    }

    public static implicit operator Nullable<T>(T value)
    {
        return new Nullable<T>(value);
    }

    public override string ToString()
    {
        if (!HasValue)
            return String.Empty;
        return this.value.ToString();
    }
}

 

在这个例子中,Nullable<T> 用 Nullable<int> 实例化。变量x现在可以用作一个 int,进行赋值或使用运算符执行一些计算。这是因为强制转换了Nullable<T> 类型的运算符。但是,x还可以为空。Nullable<T>的 HasValue 和 Value 属性可以检查是否有一个值,该值是否可以访问:

static void Main(string[] args)
{
    Nullable<int> x;
    x = 4;
    x += 3;
    if (x.HasValue)
    {
        int y = x.Value;
    }
    x = null;
}

 

posted @ 2013-08-23 19:22  罗马景行  阅读(334)  评论(0编辑  收藏  举报