对象、类和结构
C#是面向对象的编程语言,它使用类和结构来实现类型(如Windows窗口、用户界面控件和数据结构等)。C#应用程序由自定义的类和.NET Framework的类组成。
C#提供了许多功能强大的类定义方式,例如,提供不同的访问级别,从其他类继承功能,允许程序员指定实例化或销毁类型时的操作。
还可以通过使用类型参数将类定义为泛型,通过类型参数,客户端代码可以类型安全的有效方式来自定义类。客户端代码可以使用单个泛型类(例如,.NET Framework类库中的System.Collections.Generic.List)存储整数、字符串和任何其他类型的对象。
对象、类和结构具有以下特点:
l 对象是给定数据类型的实例。在执行应用程序时,数据类型为创建(或实例化)的对象提供蓝图
l 新数据类型是使用类和结构定义的
l 类和结构(包含代码和数据)组成了C#应用程序的生成块。C#应用程序始终包含至少一个类
l 结构可视为轻量类,是创建用于存储少量数据的数据类型的理想选择,不能表示以后可能要通过继承进行扩展的类型
l C#类支持继承,这意味着它们可以从先前定义的类中派生
对象
对象是具有数据、行为和标识的编程结构。对象数据包含在对象的字段、属性和事件中,对象行为则由对象的方法和接口定义。
对象具有标识——数据集相同的两个对象不一定是同一个对象。
C#中的对象通过classes和structs定义——该类型的所有对象都按照它们构成的同一蓝图操作。
对象具有以下特点:
l C#中使用的全部是对象,包括Windows窗体和控件
l 对象是实例化的;也就是说,对象是从类和结构所定义的模板中创建的
l 对象使用属性获取和更改它们所包含的信息
l 对象通常具有允许它们执行操作的方法和事件
l Visual Studio提供了操作对象的工具:使用“属性”窗口可以更改对象的属性。使用对象浏览器可以检查对象的内容
l 所有C#对象都继承自Object
类
类是C#中功能最为强大的数据类型。像结构一样,类也定义了数据类型的数据和行为。然后,程序员可以创建作为此类的实例的对象。与结构不同,类支持继承,而继承是面向对象编程的基础部分。
声明类
类是使用class关键字来定义的,如下面的示例所示:
public class Customer
{
//Fields, properties, methods and events go here...
}
class关键字前面是访问级别。在该例中,使用了public,这表示任何人都可以基于该类创建对象。类的名称位于class关键字的后面。定义的其余部分是类的主体,用于定义行为和数据。类的字段、属性、方法和事件统称为“类成员”。
创建对象
尽管有时类和对象可互换,但它们是不同的概念。类定义对象的类型,但它不是对象本身。对象是基于类的具体实体,有时称为类的实例。通过使用new关键字,后跟对象将基于的类的名称,可以创建对象,如下所示:
Customer object1 = new Customer();
创建类的实例后,将向程序员传递回对象的引用。在上例中,object1是对基于Customer的对象的引用。此引用引用新对象,但不包含对象数据本身。实际上,可以在根本不创建对象的情况下创建对象引用:
Customer object2;
建议不要创建这样的不引用对象的对象引用,因为在运行时通过这样的引用来访问对象的尝试将会失败。但是,可以创建这样的引用来引用对象,方法是创建新对象,或者将它分配给现有的对象,如下所示:
Customer object3 = new Customer();
Customer object4 = object3;
此代码创建了两个对象引用,它们引用同一个对象。因此,通过object3对对象所做的任何更改都将反映在随后使用的object4中。这是因为基于类的对象是按引用来引用的,因此类称为引用类型。
类继承
继承是通过使用派生来实现的,而派生意味着类是使用基类声明的,它的数据和行为从基类继承。通过在派生的类名后面追加冒号和基类名称,可以指定基类,如下所示:
public class Manager : Employee
{
// Employee fields, properties, methods and events are inherited
// New Manager fields, properties, methods and events go here...
}
当类声明基类时,为基类定义的所有类成员也成为新类的一部分。因为基类自身可能继承自另一个类,而后者又从另一个类继承,依此类推,最终类可能具有很多个基类。
示例
下面的示例定义一个公共类,其中包含一个字段、一个方法和一个称为构造函数的特殊方法。然后使用new关键字将该类实例化。
//Field
public string name;
//Constructor
public Person(){
name = "unknown";
}
//Method
public void SetName(string newName){
name = newName;
}
}
class TestPerson {
static void Main(){
Person person1 = new Person();
System.Console.WriteLine(person1.name);
person1.SetName("John Smith");
System.Console.WriteLine(person1.name);
}
}
结构
结构是使用struct关键字定义的,例如:
public struct PostalAddress
{
// Fields, properties, methods and events go here...
}
结构与类共享几乎所有相同的语法,但结构比类受到的限制更多:
l 尽管结构的静态字段可以初始化,结构实例字段声明还是不能使用初始值设定值
l 结构不能声明默认构造函数(没有参数的构造函数)或析构函数
结构的副本由编译器自动创建和销毁,因此不需要使用默认构造函数和析构函数。实际上,编译器通过为所有字段赋予默认值来实现默认构造函数。结构不能从类或其他结构继承。
结构是值类型——如果从结构创建一个对象并将该对象赋给某个变量,变量则包含结构的全部值。复制包含结构的变量时,将复制所有数据,对新副本所做的任何修改构不会改变旧副本的数据。由于结构不使用引用,因此结构没有标识——具有相同数据的两个值类型实例是无法区分的。
C#中的所有值类型本质上都继承自ValueType,后者继承自Object。
编译器可以在一个称为装箱的过程中将值类型转换为引用类型。
结构具有以下特点:
l 结构是值类型,而类是引用类型
l 向方法传递结构时,结构是通过传值方式传递的,而不是作为引用传递的
l 与类不同,结构的实例化可以不使用new运算符
l 结构可以声明构造函数,但它们必须带参数
l 一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自System.ValueType,后者继承自System.Object
l 结构可以实现接口
l 在结构中初始化实例字段是错误的
使用结构
truct类型适于表示Poing、Rectangle和Color等轻量对象。尽管可以将一个点表示为类,但在某些情况下,使用结构更有效。例如,如果声明一个1000个Point对象组成的数组,为了引用每个对象,则需分配更多内存;这种情况下,使用结构可以节约资源。由于.NET Framework包含名为Point的对象,因此我们转而调用结构“CoOrds”。
public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}
声明结构的默认(无参数)构造函数是错误的。总是提供默认构造函数以将结构成员初始化为它们的默认值。在结构中初始化实例字段也是错误的。
如果使用new运算符创建结构对象,则会创建该结构对象,并调用适当的构造函数。与类不同,结构的实例化可以不使用new运算符。如果不使用new,则在初始化所有字段之前,字段都保持未赋值状态且对象不可用。
对于结构,不像类那样存在继承。一个结构不能从另一个结构或类继承,而且不能作为一个类的基。但是,结构从基类Object继承。结构可实现接口,其方式同类完全一样。
与C++不同,无法使用struct关键字声明类。在C#中,类与结构在语义上是不同的。结构是值类型,而类是引用类型。
除非需要引用类型语义,否则系统将较小的类作为结构处理效率会更高。
示例1
下面的示例演示使用默认构造函数和参数化构造函数的struct初始化。
public int x,y;
public CoOrds(int p1,int p2){
x = p1;
y = p2;
}
}
// Declare and initialize struct objects
class TestCoOrds {
static void Main(){
//Initialize:
CoOrds coords1 = new CoOrds();
CoOrds coords2 = new CoOrds(10,10);
//Display results:
System.Console.Write("CoOrds 1: ");
System.Console.WriteLine("x = {0},y = {1}",coords1.x,coords1.y);
System.Console.Write("CoOrds 2: ");
System.Console.WriteLine("x = {0},y = {1}",coords2.x,coords2.y);
}
}
示例2
下面举例说明了结构特有的一种功能。它在不使用new运算符的情况下创建CoOrds对象。如果将struct换成class,程序将不会编译。
public int x,y;
public CoOrds(int p1,int p2){
x = p1;
y = p2;
}
}
// Declare a struct object without "new."
class TestCoOrdsNoNew {
static void Main(){
//Declare an object:
CoOrds coords1;
//Initialize:
coords1.x = 10;
coords1.y = 20;
//Display results:
System.Console.Write("CoOrds 1: ");
System.Console.WriteLine("x = {0},y = {1}",coords1.x,coords1.y);
}
}