什么是类
类代表一组具有公共属性和行为的对象。比如人,有眼睛、鼻子、嘴巴这些属性以及走路、说话等这些行为,这些属性和行为是公共的
C# 如何定义一个类
非常简单,使用 class 关键字并按照格式来定义即可,如下所示
代码语言:javascript复制class Person
{
}
我们可以通过修饰符来控制访问权限,如下所示
修饰符 | 访问权限 |
---|---|
private | 只有同一个类中可以访问 |
public | 同一程序集或引用该程序集的其他程序集都可以访问 |
protected | 只有同一个类或派生类中可以访问 |
internal | 只有同一个程序集中可以访问 |
protected internal | 在同一个程序集、该类和派生类中可以访问 |
类的成员
字段
字段由三部分组成:访问修饰符、字段的类型、字段名称
代码语言:javascript复制public class Person
{
private string name;
}
字段可以使用关键字 readonly 和 const 来定义字段
代码语言:javascript复制public class Person
{
private readonly string name;
public const int age = 18;
}
以上代码,若使用 readonly 来修饰字段,则不需要再定义时初始化,而是可以在构造函数中再完成初始化;但若使用 const 修饰字段,如果没有在定义字段时初始化,就会产生编译错误
如前所述,你也可以使用 static 关键字来声明静态字段,区别就是静态字段必须通过类来访问
属性
属性是对字段的扩展。根据面向对象语言的封装思想,字段最好设为 private,因为这样可以防止客户端之间对字段进行篡改,从而保证了内部成员的完整性。于是为了访问类中的私有字段,C# 提供了属性这种机制,用来对字段进行灵活的控制和访问
代码语言:javascript复制public class Person
{
private string name;
public string Name
{
get
{
return name;
}
set
{
// do something
name = value;
}
}
}
方法
方法由方法签名和一系列语句的代码块组成。其中,方法签名包括方法的访问级别(public 或 private)、可修饰符、方法名称和参数
代码语言:javascript复制public class Person
{
public void Speak(string msg)
{
Console.WriteLine(msg);
}
}
构造函数
构造函数主要用于创建类的实例对象。构造函数分为实例构造函数和静态构造函数两种。
1、实例构造函数
代码语言:javascript复制public class Person
{
private string name;
public Person()
{
name = "Carl";
}
}
该构造函数具有以下特点:
- 构造函数可以进行方法重载,你可以定义多个构造函数
- 如果没有显示定义一个构造函数,C# 编译器会自动生成一个函数体为空的无参实例构造函数
- 可以对实例构造函数指定访问级别
- 构造函数必须与类同名
- 构造函数不允许有返回类型
2、静态构造函数
静态构造函数用于初始化类中的静态成员,在创建第一个实例或引用任何静态成员之前,CLR 都将自动调用静态构造函数
代码语言:javascript复制public class Person
{
private static string name;
static Person()
{
name = "Carl";
}
}
注意,静态构造函数只执行一次,与实例构造函数一样,要成为静态构造函数必须具有以下特点
- 静态构造函数不能使用任何访问修饰符
- 静态构造函数不能带有任何参数
- 静态构造函数只会执行一次
- 不能直接调用静态构造函数
- 在程序中,程序员无法控制执行静态构造函数的时机
析构函数
析构函数用于在类销毁之前释放类实例所使用的托管和非托管资源。对于 C# 应用程序所创建的大多数对象,可以依靠 .Net Framework 的垃圾回收期来隐式地执行内存管理任务。但若创建了非托管资源的对象,在应用程序使用完这些非托管资源之后,垃圾回收期将运行对象的析构函数来释放这些资源
代码语言:javascript复制public class Person
{
~Person()
{
Console.WriteLine("析构函数被调用了");
}
}
该析构函数隐式地调用了基类 Object 的 Finalize 方法,上面析构函数将被隐式转换为如下代码:
代码语言:javascript复制protected override void Finalize()
{
try
{
Console.WriteLine("析构函数被调用了");
}
finally
{
base.Finalize();
}
}
在定义析构函数时需要注意以下几点:
- 不能在结构体中定义析构函数,只能对类使用析构函数
- 一个类只能由一个析构函数
- 无法继承或重载析构函数
- 无法显示地调用析构函数,析构函数时由垃圾回收期自动调用地
- 析构函数没有修饰符也没有参数
索引器
当一个类包含数组成员时,索引器将大大地简化对类中数组成员地访问。索引器的定义类似于属性,也具有 get 和 set 访问器。具体定义如下
代码语言:javascript复制private object this[string index]
{
get{ // 返回类中数组某个元素 }
set{ // 对类中数组元素赋值 }
}
类实例化
定义完类,我们必须通过类的实例对象才能访问
代码语言:javascript复制Person p = new Person();
p.Speak();
Console.WriteLine(p.name);
类于结构体的区别
由于类和结构体在语法和使用上非常相似,以至于一些初学者经常会混淆。我们将两者进行对比
- 语法上区别,定义类使用关键字 class,定义结构体使用关键字 struct
- 结构体中不可对声明字段进行初始化赋值,而类可以
- 如果类没有创建构造函数,那么编译器会自动生成隐式构造函数,而结构体无论是否显示定义,隐式构造函数都是一直存在的
- 结构体无法显示地定义无参数的构造函数
- 结构体的构造函数中,必须要为结构体中的所有字段赋值
- 创建结构体对象可以不使用 new,而类必须使用 new 初始化
- 结构体不能继承结构或者类
- 类时引用类型,结构体是值类型
- 结构体不能定义析构函数,类可以
- 不能使用 abstract 和 sealed 关键字修饰结构体,而类可以
namespace Demo
{
class Program
{
public class Point
{
private int x;
private int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
struct Point2
{
private int x;
private int y;
public Point2(int x, int y)
{
this.x = x;
this.y = y;
}
}
static void Main(string[] args)
{
var p = new Point(1, 2);
var p2 = new Point2(1, 2);
Console.WriteLine(p);
Console.WriteLine(p2);
Console.ReadKey();
}
}
}
归纳总结
这里主要介绍了 C# 中的类和类成员的定义,最后又介绍了类和结构体的区别,根据场景去选择使用