其实在介绍Struct之前,我们应对C#关于类(Class)的原理进行初步的研究。但是,从另一个方面,我们也可以先对这个与类有着血缘关系的结构进行探讨以获得对类的进一步的认识。 首先,C#的结构是一个关系重大的语言功能。和类一样,结构也可以包含其他类型。由于结构在内部是值类型的,所以结构有时也被称为类的轻型版本。同时,结构不承担引用对象所带来的开销,除非在对其装箱时例外。 结构也有其重要的限制,所以导致他只能用于非常特殊的场合。 以下就讨论他们的局限性和他的优点。 结构的定义和类的定义基本上是一致的: [attributes][modifiers] struct [:interfaces] { [struct-body] }[;] 为了便于理解,我举个实例来展开论述。我们首先定义一个描述具体事物的结构体——"611311班"。 struct STUClass{ public string ClassName; public object ClassMumber; public int ClassNumber; } 到目前为止,这个声明很像一个类。但是,下面你将看到在使用结构方面的许多限制。 客户不必对结构进行实例化(通过new关键字)。这是因为,作为一种值类型,结构一旦被声明,就被分配。 但是正是有了这种用法,所以我们如果不亲自对结构的成员进行显式的初始化(使用new关键字),那么字段就不会被初始化。如下面这段代码,编译将会出错: STUClass s611311; Console.WriteLine(s611311.ClassName); 以下的代码将会纠正这个错误。注意,因为s611311.ClassName 是一个值类型,所以初始化模认为 0 ; STUClass s611311 = new STUClass(); Console.WriteLine(s611311.ClassName); 我所知的结构成员包括构造器、常量、字段、方法、特性、索引器、操作符等类型。但是,在构造器方面,结构有个非常重要的限制:不能位结构创建无参数的构造器。 所以,以下代码不能编译通过: struct STUClass{ public STUClass(); public string ClassName; public object ClassMember; public int ClassNumber; } 但是,我们可以利用带有参数的构造器原型来定义: struct STUClass{ public STUClass(string name,object menber,int number) { ClassName = name; ClassMember = menber; ClassNumber = number; } public string ClassName; public object ClassMember; public int ClassNumber; } 如果仔细研究一下定义结构的语法,会注意到其中没有基类的列表。这是由于结构不能基于其他结构或类,而且他们也不能作为其他结构或类的基。如果希望看到更加直观的结论,你最好到.Net 开发环境中分别定义一个具有相同成员的类和结构,然后到编译器产生的MSIL中去比较一下。 从中我们可以得出一下结论:1、结构的定义是封闭的(不能作为基类使用);2、结构隐式地派生自System.ValueType, 而System.ValueType是所有值类型的超类型(终极基类)。3、结构没有默认的构造器。 (欲知使用结构的原则和例程,且看下回分晓...)
这里我将接着介绍在使用结构时应该注意和把握的原则: 通过上篇的介绍,我们可以很自然的意识到结构在效率上的优越性(相对于类),这主要归因于它们在底层的值类型结构。 不过,它们的对于大容量数据和复杂度高的算法进行处理时所表现出来的局限性,使得它的适用范围大受限制。那我们在什么情 况下使用结构才能不受指责和嘲笑呢? 1、如果你正在从事图像色彩或是固定模式的业务处理程序的设计,或者你在设计对象群时,需要面对大量结构简单且状态 信息比较少的对象时,我建议你最好选用结构类型来构造这些小规模数据体。 2、由于结构的原型是值类型,所以它整个被定义为一个数据,所以不要试图在结构里构造过多的方法,最好是能不定义方 法,就尽量避免。
我们来看以下微软提供的一个最具代表性的例子: RGB结构 using System;
/// <summary> /// RGB结构 /// </summary> struct RGB { public static readonly RGB RED = new RGB(255,0,0); public static readonly RGB GREEN = new RGB(0,255,0); public static readonly RGB BLUE = new RGB(0,0,255); public static readonly RGB WHITE = new RGB(255,255,255); public static readonly RGB BLACK = new RGB(0,0,0);
public int Red; public int Green; public int Blue; public RGB(int red,int green,int blue) { Red = red; Green = green; Blue = blue; } public override string ToString() { return (Red.ToString("X2") + Green.ToString("X2") + Blue.ToString("X2")); } }
public class Struct { static void OutPutRGBValue(string color,RGB rgb) { Console.WriteLine("The Value for {0} is {1}",color,rgb); }
static void Main(string[] args) { OutPutRGBValue("red",RGB.RED); OutPutRGBValue("green",RGB.GREEN); OutPutRGBValue("blue",RGB.BLUE); OutPutRGBValue("white",RGB.WHITE); OutPutRGBValue("black",RGB.BLACK); } } 以上的例子中我们定义了一个结构和静态字段,这样做使我们存储的效率提高了;使用上又方便了用户,毕竟记住一个 RGB(255,100,255) 要比记住一个“草浅兰” 要困难的多;由于静态成员的加盟,使得每个RGB键值对于整个系统只用定义 一次,这样使用起来其高效性和方便性都是显而易见的。
作者Blog:http://blog.csdn.net/heiding/
|