首页 > 代码库 > 类和结构

类和结构

类和结构实际上都是创建对象的模板,每个对象都包含数据,并提供了处理和访问数据的方法。
类定义了类的每个对象(称为实例)可以包含什么数据和功能。

结构与类的区别是它们在内存中的存储方式、访问方式(类是存储在堆heap)上的引用类型,而
结构是存储在栈(stack上的值类型)和它们的一些特征(如结构不支持继承)。较小的数据类型使用结
构可提高性能。但在语法上,结构与类非常相似,主要的区别是使用关键字siuct代替dass来声明
结构。

类中的数据和函数称为类的成员。Microsoft的正式术语对数据成员和函数成员进行了区分。除

了这些成员外,类还可以包含嵌套的类型(如其他类)。成员的可访问性可以是public、protected、internal protected、private或internal。

数据成员

数据成员是包含类的数据——字段、常量和事件的成员。数据成员可以是静态数据。类成员总
是实例成员,除非用static进行显式的声明。

函数成员

函数成员提供了操作类中数据的某些功能,包括方法、属性、构造函数和终结器(finalizer)、运
算符以及索引器。
  方法是与某个类相关的函数,与数据成员一样,函数成员默认为实例成员,使用盹吮修饰
符可以把方法定义为静态方法。
  属性是可以从客户端访问的函数组,其访问方式与访问类的公共字段类似。唧为读写类中
的属性提供了专用语法,所以不必使用那些名称中嵌有Get或set的方法。因为属性的这种
语法不同于一般函数的语法,在客户端代码中,虚拟的对象被当做实际的东西。
  构造函数是在实例化对象时自动调用的特殊函数。它们必须与所属的类同名,且不能有返
回类型。构造函数用于初始化字段的值。
  终结器类似于构造函数,但是在CLR检测到不再需要某个对象时调用它。它们的名称与类
相同,但前面有一个“~” 符号。不可能预测什么时候调用终结器。

  运算符执行的最简单的操作就是加法和减法。在两个整数相加时,严格地说,就是对整数
使用“十”运算符。C#允许指定把已有的运算符应用于自己的类(运算符重载)
  索引器允许对象以数组或集合的方式进行索引。

给方法传递参数

参数可以通过引用或通过值传递给方法。在变量通过引用传递给方法时,被调用的方法得到的
就是这个变量,所以在方法内部对变量进行的任何改变在方法退出后仍旧有效。而如果变量通过值
传送给方法,被调用的方法得到的是变量的一个相同副本,也就是说,在方法退出后,对变量进行
的修改会丢失。对于复杂的数据类型,按引用传递的效率更高,因为在按值传递时,必须复制大量
的数据。
在c#中,除非特别说明,所有的参数都通过值来传递。但是,在理解引用类型的含义时需要注
意。因为引用类型的变量只包含对象的引用,将要复制的正是这个引用,而不是对象本身,所以对
底层对象的修改会保留下来。相反,值类型的对象包含的是实际数据,所以传递给方法的是数据本
身的副本。例如,int通过值传递给方法,对应方法对该int的值所做的任何改变都没有改变原int
对象的值。但如果把数组或其他引用类型伸日类)传递给方法,对应的方法就会使用该引用改变这个数组中的值,而新值会反射在原始数组对象上。

using system;

namespace Wrox

{

class ParameterTest

{

static void SomeFunction(int[] ints,int i)

{

ints[0]=100;

i=100;

}

public static int Main()

{

int i=0;

int []ints={0,1,2,3,4,8};

Console.WriteLine("i = "+ i);

Console.WriteLine("ints[0] =" + ints[0]);

Console.WriteLine("Calling SomeFunction");

Console.WriteLine("i = "+ i);

Console.WriteLine("ints[0] =" + ints[0]);

return 0;

}

}

}

结果如下:

i = 0

ints[0]= 0

Calling SomeFunction

i=0;

ints[0]=100

ref参数

如前所述,通过值传送变量是默认的,也可以道使值参数通过引角传送给方法。为此,要使用

ref关键字。如果把一个参数传递给方法,且这个方法的输入参数前带有ref关键字,则该方法对变
量所做的任何改变都会影响原始对象的值:

static void someFunction〈int[] ints, ref int i)
{

ints[0]=100
i = 100; // The change to i will persist after someFunction() exits.
{
在调用该方法时,还需要添加ref关键字:

SomeFunction(ints,ref i);

最后,C#仍要求对传递给方法的参数进行初始化,理解这一点也非常重要。在传递给方法之前,
无论是按值传递,还是按引用传递;任何变量都必须初始化。

out参数

在C风格的语言中,函数常常能从一个例程中输出多个值,这使用输出参数实现,只要把输出
的值赋予通过引用传递给方法的变量即可。通常,变量通过引用传递的初值并不重要,这些值会被
函数重写,函数甚至从来没有使用过它们。
如果可以在C#中使用这种约定,就会非常方便。但C#要求变量在被引用前必须用一个初值进
行初始化。尽管在把输入变量传递给函数前,可以用没有意义的值初始化它们,因为函数将使用真
实、有意义的值初始化它们,但是这样做是没有必要的,有时甚至会引起混乱。但有一种方法能够
简化C#编译器所坚持的输入参数的初始化。
编译器使用out关键字来初始化。在方法的输入参数前面加上out前缀时,传递给该方法的变
量可以不初始化。该变量通过引用传递,所以在从被调用的方法中返回时,对应方法对该变量进行
的任何改变都会保留下来。

类和结构