定义类
C#中的类定义
C#使用class关键字来定义类:
class MyClass
{
// Class members.
}
默认情况下,类声明为内部的,即只有当前工程中的代码才能访问
也可以用internal关键字显式声明:
internal class MyClass
{
// Class members.
}
可以指定类是公共的,即可以由其他工程中的代码来访问
要用public关键字声明:
public class MyClass
{
// Class members.
}
还可以指定类是
抽象类:不能实例化,只能继承,可以有抽象成员,使用关键字abstract
密封类:不能继承,使用关键字sealed
声明抽象类:
public abstract class MyClass
{
// Class members, may be abstract.
}
抽象类可以是public的,也可以是internal的
声明密封类:
public sealed class MyClass
{
// Class members.
}
抽象类可以是public的,也可以是internal的
可以在类定义中指定继承,方式是类名后加冒号再加基类名:
public class MyClass : MyBase
{
// Class members.
}
注意:在C#中只能有一个基类,如果继承了个抽象类,就必须执行所继承的所有抽象成员(除非派生类也是抽象的)
编译器不允许派生类的可访问性比其基类更高
即内部类可以继承于一个公共类,但公共类不能继承于一个内部类
如果没有指定基类,那么被定义的类继承自System.Object
还可以在冒号后面指定支持的接口
如果指定了基类,冒号后面跟着基类名,再接着一个或多个指定的接口,之间用逗号分割
例如:
给MyClass指定一个接口:
public class MyClass : IMyInterface
{
// Class members.
}
给MyClass指定基类和接口:
public class MyClass : MyBase, IMyInterface
{
// Class members.
}
指定多个接口:
public class MyClass : MyBase, IMyInterface, IMySecondInterface
{
// Class members.
}
访问修饰符组合:
修饰符 含义
none or internal 类只能在当前工程中访问
public 类可以在任何地方访问
abstract or internal abstract 类只能在当前工程中访问,不能实例化,只能继承
public abstract 类可以在任何地方访问,不能实例化,只能继承
sealed or internal sealed 类只能在当前工程中访问,不能派生,只能实例化
public sealed 类可以在任何地方访问,不能派生,只能实例化
接口的定义
与类的声明方式类似,使用interface关键字:
interface IMyInterface
{
// Interface members.
}
修饰符关键字public和internal的使用方式相同:
public interface IMyInterface
{
// Interface members.
}
关键字abstract和sealed不能在接口中使用
因为接口不包含执行代码,不能直接实例化,而且必须可以继承
接口继承跟类相似,不过可以使用多个基接口:
public interface IMyInterface : IMyBaseInterface, IMyBaseInterface2
{
// Interface members.
}
接口不是类,不从System.Object继承
由于多态性使System.Object的成员可以使用这些接口
System.Object
公共构造函数
Object 初始化 Object 类的新实例。
公共方法
Equals 已重载。 确定两个 Object 实例是否相等。
GetHashCode 用作特定类型的哈希函数。
GetType 获取当前实例的 Type。
ReferenceEquals 确定指定的 Object 实例是否是相同的实例。
ToString 返回表示当前 Object 的 String。
受保护的方法
Finalize 析构函数
MemberwiseClone 创建当前 Object 的浅表副本。
构造函数和析构函数
在C#中定义类,一般不需要定义构造函数和析构函数
也可以自定义构造函数和析构函数
例如:
class MyClass
{
public MyClass()
{
// Constructor code.
}
}
这个构造函数与包含它的类同名,没有参数(作为默认构造函数),是一个公共函数,可以被实例化
使用使用私有默认构造函数,对象不能被实例化
例如:
class MyClass
{
private MyClass()
{
// Constructor code.
}
}
可以添加非默认构造函数,方法是添加参数
例如:
class MyClass
{
public MyClass()
{
// Default constructor code.
}
public MyClass(int myint)
{
// Nondefault constructor code (uses myInt).
}
}
构造函数的个数没有限制的
在.NET中使用的析构函数叫Finalize(),但不建议重写这个函数
使用下面的方式重写析构函数:
class MyClass
{
~MyClass()
{
// Destructor body.
}
}
构造函数的执行序列
默认情况下,为了实例化派生的类,必须实例化它的基类,接着必须实例化这个基类的基类,直到实例化System.Object为止
对于非默认构造函数,在其基类上使用匹配这个构造函数签名的构造函数,如果没有这样的构造函数,才使用默认构造函数
例如:
public class MyBaseClass
{
public MyBaseClass()
{
}
public MyBaseClass(int i)
{
}
}
public class MyDerivedClass : MyBaseClass
{
public MyDerivedClass()
{
}
public MyDerivedClass(int i)
{
}
public MyDerivedClass(int i, int j)
{
}
}
以下面方式实例化对象:
MyDerivedClass myObj = new MyDerivedClass();
以下序列事件将发生:
System.Object.Object()
MyBaseClass.MyBaseClass()
MyDerivedClass.MyDerivedClass()
以下面方式实例化对象:
MyDerivedClass myObj = new MyDerivedClass(4);
以下序列事件将发生:
System.Object.Object()
MyBaseClass.MyBaseClass(int i)
MyDerivedClass.MyDerivedClass(int i)
以下面方式实例化对象:
MyDerivedClass myObj = new MyDerivedClass(4, 8);
以下序列事件将发生:
System.Object.Object()
MyBaseClass.MyBaseClass()
MyDerivedClass.MyDerivedClass(int i, int j)
用base关键字可以指定在派生类的构造函数定义中所使用的基类的构造函数:
例如:
public class MyDerivedClass : MyBaseClass
{
...
public MyDerivedClass(int i, int j) : base(i)
{
}
}
或者直接指定字面值:
public class MyDerivedClass : MyBaseClass
{
...
public MyDerivedClass(int i, int j) : base(5)
{
}
}
以下面方式实例化对象:
MyDerivedClass myObj = new MyDerivedClass(4, 8);
以下序列事件将发生:
System.Object.Object()
MyBaseClass.MyBaseClass(int i)
MyDerivedClass.MyDerivedClass(int i, int j)
使用this关键字可以指定在调用指定的构造函数前,使用非默认构造函数
例如:
public class MyDerivedClass : MyBaseClass
{
public MyDerivedClass() : this(5, 6)
{
}
...
public MyDerivedClass(int i, int j) : base(i)
{
}
}
以下面方式实例化对象:
MyDerivedClass myObj = new MyDerivedClass();
以下序列事件将发生:
System.Object.Object()
MyBaseClass.MyBaseClass(int i)
MyDerivedClass.MyDerivedClass(int i, int j)
MyDerivedClass.MyDerivedClass()
唯一的限制是使用this或base关键字只能指定一个构造函数
不过还是可以构造相当复杂的执行序列
VisuaI Studio .NET中的OOP工县
“类视图”窗口
这个窗口显示了应用程序中的层次结构,查看我们使用的类的特性
除了可以查看信息外,还可以访问许多项目的相关代码
对象浏览器
对象浏览器可以查看工程中能使用的其他类,甚至可以查看外部的类
添加类
类库工程
类库是指一个只包含类(以及其他相关的类定义,但没有入口点)的工程
类库工程编译为.dll装配件,其他工程中添加对类库工程的引用就可以访问它的内容
类库可以进行修改和更新而不影响使用它的工程
创建类库:
1 选择“添加”,“新建项”,“类库”创建一个类库
2 在类库中将自动新建一个Class1.cs文件,重命名为MyExternalClass.cs
3 MyExternalClass.cs中的代码会自动改为
public class MyExternalClass
{
}
4 选择“添加”,“新建项”,“类”创建一个类,命名为MyInternalClass.cs
5 修改代码使之成为一个内部类
internal class MyInternalClass
{
}
6 编译工程(选择“生成”,“生成解决方案”来构建它)
将在相应目录生成一个dll文件
7 选择“添加”,“新建项目”,“控制台应用程序”,创建一个控制台应用程序工程
8 选择“添加引用”,“浏览”,选择刚才生成的dll文件
9 查看工程的引用项目,应该添加了一个类库的引用
10 查看对象浏览器,应该添加了一个类库的引用
11 修改控制台应用程序工程的Program.cs的代码
using System;
using System.Collections.Generic;
using System.Text;
using ClassLibrary1;//添加类库的引用
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyExternalClass myObj = new MyExternalClass();
Console.WriteLine(myObj.ToString());
Console.ReadKey();
}
}
}
12 调试运行,将显示:ClassLibrary1.MyExternalClass
接口和抽象类
相似:
都包含可以由派生类继承的成员
都不能直接实例化,但可以通过多态性声明他们的变量
例如:
接口IA的派生类ClassB
不能直接实例化就是不能
IA oA = new IA();
但由于多态性可以:
IA oA = new ClassB();
根据多态性的规则,这样实例化的对象不能访问派生对象的其他成员
区别:
一个派生类只能直接继承一个抽象类(但可以用继承链包含多个抽象类)
类可以使用任意多个接口
抽象类可以拥有抽象成员和非抽象成员,可以是私有的、公共的、受保护的、内部的或受保护的内部成员
接口成员必须都在使用接口的类上执行,他们没有代码体,而且是公共的,不能包含字段、构造函数、析构函数、静态函数或常量。
用途:
抽象类主要用作对象系列的基类,共享某些主要特性,例如目的和结构
接口主要由类来使用,这些类具有某个相同的特性,由接口来结合这些特性
结构类型
结构和类非常相似,但结构是值类型,而类是引用类型
例如:
对于类ClassA,有一个类成员int b
ClassA oA = new ClassA();
ClassA oB = oA;
oA.b = 10;
oB.b = 20;
结果输出
oA.b和oB.b的值都是20
对于结构StructA,有一个结构成员int b
StructA oA = new StructA();
StructA oB = oA;
oA.b = 10;
oB.b = 20;
结果输出
oA.b的值是10,oB.b的值是20
说明:
对象是引用类型,变量赋給对象量时,实际上是把指向该变量的指针赋給对象,当对象再给其他对象赋值,只是把指针复制给那个对象,所以指向的是同一个变量
结构是值类型,其变量包含的是结构本身,所以对象中的结构是各自独立的
阴影和深度复制
按照成员复制简单的对象可以通过派生于System.Object的MemberwiseClone()方法完成
这是一个受保护的方法,可以定义一个公共方法来调用它
这个方法提供的复制功能叫阴影复制
它没有考虑引用类型成员,这样新对象中的引用就会指向于源对象中相同成员的对象
接口ICloneable,执行它的Clone()方法,如果愿意可以进行深度复制