跳到主要内容

C# 类和对象

本章将深入讲解 C# 中类的定义、成员、以及对象的创建和使用。

类的成员类型

字段

class Person
{
// 实例字段
private string _name;
public int _age;

// 静态字段
public static int TotalCount = 0;

// 常量(编译时确定)
public const string DefaultCity = "北京";

// 只读字段(只能在构造函数或初始化器中赋值)
public readonly string Id;

public Person(string id)
{
Id = id; // 只读字段只能在构造函数中赋值
TotalCount++; // 每次创建实例,静态字段加1
}
}

属性

class Student
{
// 自动实现属性
public string Name { get; set; }

// 带验证的属性
private int _score;
public int Score
{
get => _score;
set
{
if (value < 0 || value > 100)
throw new ArgumentException("分数必须在0-100之间");
_score = value;
}
}

// 只读属性
public bool IsPassed => Score >= 60;

// 只写属性
private string _password;
public string Password
{
set => _password = value;
}

// 表达式属性(C# 6+)
public string Info => $"姓名: {Name}, 分数: {Score}";
}

方法

class Calculator
{
// 实例方法
public int Add(int a, int b) => a + b;

// 静态方法
public static int Multiply(int a, int b) => a * b;

// 虚方法(可被重写)
public virtual string GetDescription() => "计算器";

// 抽象方法(在抽象类中)
// public abstract int Calculate();

// 异步方法
public async Task<int> FetchDataAsync()
{
await Task.Delay(100);
return 42;
}

// 局部方法(C# 9+)
public void Process(int value)
{
int LocalSquare(int x) => x * x;
Console.WriteLine(LocalSquare(value));
}
}

索引器

class Company
{
private string[] _employees = new string[100];
private int _count = 0;

// 索引器
public string this[int index]
{
get
{
if (index >= 0 && index < _count)
return _employees[index];
return null;
}
set
{
if (index >= 0 && index < _count)
_employees[index] = value;
}
}

// 字符串索引器
public string this[string name]
{
get
{
for (int i = 0; i < _count; i++)
{
if (_employees[i] == name)
return _employees[i];
}
return null;
}
}

public void AddEmployee(string name)
{
if (_count < 100)
_employees[_count++] = name;
}
}

// 使用
Company company = new Company();
company.AddEmployee("张三");
company.AddEmployee("李四");
Console.WriteLine(company[0]); // 张三
Console.WriteLine(company["张三"]); // 张三

事件

class Button
{
// 定义事件
public event EventHandler Click;

// 触发事件的方法
public void OnClick()
{
// 检查是否有订阅者
Click?.Invoke(this, EventArgs.Empty);
}
}

// 使用
Button btn = new Button();
btn.Click += (s, e) => Console.WriteLine("按钮被点击!");
btn.OnClick();

运算符

struct Point
{
public int X { get; set; }
public int Y { get; set; }

// 重载 + 运算符
public static Point operator +(Point a, Point b)
=> new Point(a.X + b.X, a.Y + b.Y);

// 重载 == 运算符
public static bool operator ==(Point a, Point b)
=> a.X == b.X && a.Y == b.Y;

public static bool operator !=(Point a, Point b)
=> !(a == b);

// 一元运算符
public static Point operator -(Point p)
=> new Point(-p.X, -p.Y);
}

// 使用
Point p1 = new Point(1, 2);
Point p2 = new Point(3, 4);
Point p3 = p1 + p2; // (4, 6)

嵌套类

class Outer
{
public class Inner
{
public void Method() => Console.WriteLine("Inner method");
}

private class SecretInner
{
}
}

Outer.Inner inner = new Outer.Inner();
inner.Method();

对象的创建和使用

使用 new 创建对象

class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

// 方式1:使用构造函数
Person p1 = new Person();
p1.Name = "张三";
p1.Age = 20;

// 方式2:使用对象初始化器
Person p2 = new Person { Name = "李四", Age = 25 };

// 方式3:带构造函数的初始化器
Person p3 = new Person("王五") { Age = 30 };

对象初始化器

class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string[] Courses { get; set; }
}

// 使用对象初始化器
var student = new Student
{
Name = "张三",
Age = 20,
Courses = new[] { "数学", "英语" }
};

// 集合初始化器
var list = new List<Student>
{
new Student { Name = "张三", Age = 20 },
new Student { Name = "李四", Age = 22 }
};

匿名类型

// 创建匿名类型
var person = new { Name = "张三", Age = 20 };

// 使用
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

// 数组
var people = new[]
{
new { Name = "张三", Age = 20 },
new { Name = "李四", Age = 25 }
};

this 关键字

class Person
{
private string _name;
private int _age;

public Person(string name, int age)
{
// 使用 this 区分参数和字段
this._name = name;
this._age = age;
}

// 链式调用
public Person SetName(string name)
{
this._name = name;
return this; // 返回当前对象
}

public Person SetAge(int age)
{
this._age = age;
return this;
}

public void Print() => Console.WriteLine($"{_name}, {_age}");
}

// 使用
new Person("张三", 20)
.SetName("李四")
.SetAge(25)
.Print();

基类和继承

继承语法

// 基类
class Animal
{
public string Name { get; set; }
public virtual void Speak() => Console.WriteLine("...");

public void Eat() => Console.WriteLine("吃东西");
}

// 派生类
class Dog : Animal
{
// 重写基类方法
public override void Speak() => Console.WriteLine("汪汪!");

// 新增方法
public void Fetch() => Console.WriteLine("捡球");
}

class Cat : Animal
{
public override void Speak() => Console.WriteLine("喵喵!");
}

base 关键字

class Person
{
public string Name { get; set; }
public int Age { get; set; }

public Person(string name, int age)
{
Name = name;
Age = age;
}
}

class Student : Person
{
public string School { get; set; }

public Student(string name, int age, string school)
: base(name, age) // 调用基类构造函数
{
School = school;
}

public new void PrintInfo()
{
// 调用基类的方法
base.Eat();
Console.WriteLine($"姓名: {Name}, 年龄: {Age}, 学校: {School}");
}
}

类型检查

is 运算符

object obj = new Dog();

if (obj is Dog)
{
Dog dog = (Dog)obj;
dog.Speak();
}

// C# 7+ 模式匹配
if (obj is Dog d)
{
d.Speak(); // 直接使用 d
}

// 加上类型判断(C# 9+)
if (obj is not null and Dog d)
{
d.Speak();
}

as 运算符

object obj = "Hello";

// 使用 as 进行安全转换
string? s = obj as string;
if (s != null)
{
Console.WriteLine(s.Length);
}

// 或使用空合并
string s2 = obj as string ?? "默认字符串";

密封类

// sealed 修饰的类不能被继承
sealed class SealedClass
{
public void Method() { }
}

// 密封方法
class BaseClass
{
public virtual void Method() { }
}

class DerivedClass : BaseClass
{
// 密封方法,阻止进一步重写
public sealed override void Method() { }
}

部分类

// 文件1: Person.Part1.cs
partial class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

// 文件2: Person.Part2.cs
partial class Person
{
// 完整姓名属性
public string FullName => $"{FirstName} {LastName}";

public void Print() => Console.WriteLine(FullName);
}

记录(C# 9+)

// 简单记录
record Person(string Name, int Age);

// 使用
var p1 = new Person("张三", 20);
var p2 = p1 with { Age = 21 }; // 创建副本

// 值相等
Console.WriteLine(p1 == p2); // True(内容相同)

小结

  1. 字段:实例字段、静态字段、常量、只读字段
  2. 属性:自动实现、验证、只读、计算属性
  3. 方法:实例方法、静态方法、虚方法、异步方法
  4. 索引器:类似数组访问的语法糖
  5. 事件:发布-订阅模式
  6. 继承:extends、base 关键字
  7. 模式匹配:is、as 运算符

练习

  1. 创建一个表示银行账户的类,包含余额属性和存取款方法
  2. 使用索引器创建一个类似数组的集合类
  3. 创建一个密封类并尝试继承,验证错误
  4. 使用记录类型创建一个不变的学生信息类型