C# 学习笔记(3)—— 类和结构体

2023-10-20 18:47:15 浏览数 (1)

什么是类

类代表一组具有公共属性和行为的对象。比如人,有眼睛、鼻子、嘴巴这些属性以及走路、说话等这些行为,这些属性和行为是公共的

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 关键字修饰结构体,而类可以
代码语言:javascript复制
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# 中的类和类成员的定义,最后又介绍了类和结构体的区别,根据场景去选择使用

0 人点赞