结构的用法
一、为什么使用结构,而不是类?
结构可以像类一样,封装有各种数据、类型和函数成员。不过与类不同的是,它是一个值类型。假设有一个类:
class Size
{
int Width;
int Height;
}
这个类只是存储两个int类型的数据而已,而没有别的意义,在这种情况下,为了获得更好的性能,可以使用结构为定义:
struct Size
{
public int Width;
public int Height;
}
为什么说结构具有比类更好的性能?这是因为结构是值类型,其数据存放在栈或存储为内联(inline)中(如果它是对象的一部分,则也会保存在堆中),其分配更快于引用类型,且当其值离开作用域时就会立即被收回。
不过,如果把结构作为参数来传递,或把一个结构赋值给另一个结构时,就会大量地复制结构的内容,如果结构的内容很大,则系统的开销是非常大的。所以从这个角度上来说,结构只适合于较小的数据。
有一个方法可以避免当结构做为参数传递时,会涉及到大量的数据被复制的问题,那就是把结构做为ref参数来传递。这样只传递结构在内存中的地址,即引用,而不会复制数据。
二、结构与继承
结构本身不支持继承,但却可以提供一个或多个接口来实现。
结构隐式地继承自System.ValueType,而后者又继承自System.Object类,所以结构能访问System.Object类中的三个方法:Equals()、ToString()、GetHashTable(),包括重写,比如,一个较有用的就是重写ToString()方法。看下面的例子:
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Size s= new Size();
s.Width = 2;
s.Height = 3;
//最后的输出是2+3
Console.WriteLine(s.ToString());
Console.ReadLine();
}
}
public struct Size
{
public int Width;
public int Height;
public override string ToString()
{
return Width.ToString() + "+" + Height.ToString();
}
}
三、结构的构造函数
结构提供了默认的构造函数,而且把所有字段隐式地初始化为0;比如上面的这个结构,会自动地把Width和herght初始化为0。因此,在定义结构时,不能够定义字段的初始值以绕开默认的构造函数。比如下面这段代码将不会编译通过(但如果是类就可以):
public struct Size
{
public int Width = 2;
public int Height = 3;
public override string ToString()
{
return Width.ToString() + "+" + Height.ToString();
}
}
同时,也不能声明不带参数的构造函数(因为默认的构造函数并不带有参数),但可以像类一样结构提供除了默认以外的构造函数,以对其字段进行初始化,比如如下代码:
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Size s1 = new Size();
Size s2 = new Size(2,3);
//最后的输出是0+0
Console.WriteLine(s1.ToString());
//最后的输出是2+3
Console.WriteLine(s2.ToString());
Console.ReadLine();
}
}
public struct Size
{
public int Width;
public int Height;
public Size(int intWidth,int intHeight)
{
this.Width = intWidth;
this.Height = intHeight;
}
public override string ToString()
{
return Width.ToString() + "+" + Height.ToString();
}
}
声明结构时,可以像类一样使用new关键字,则系统会自动初始化结构并分配内存(注意:在这里使用new关键字,并不是创建一个实例,因为这不是类)。也可以不使用new关键字,如果不使用则一样可以声明,但却没有进行初始化(当然已经分配空间了),看以下代码:
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Size s1 = new Size();
Size s2;
//如果没有这两句,s2.ToString()将会出错,因为没有初始化变量(s2)。
s2.Width=2;
s2.Height = 3;
//最后的输出是0+0
Console.WriteLine(s1.ToString());
//最后的输出是2+3
Console.WriteLine(s2.ToString());
Console.ReadLine();
}
}
public struct Size
{
public int Width;
public int Height;
public override string ToString()
{
return Width.ToString() + "+" + Height.ToString();
}
}
结构可以像类一样提供Close()和Dispose()方法,但不能提供Finaliza()方法,因为此方法是应用于对象,由垃圾收集器调用,而结构是值类型,所以无法调用此方法。
结构的任何成员不允许声明为virtual,因为结构不允许被继承;也不允许声明为abstract,因为结构不允许成为其他类的基类;同时,也不允许使用关键字sealed,因为它是隐式密封的,已默认为sealed。