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(内容相同)
小结
- 字段:实例字段、静态字段、常量、只读字段
- 属性:自动实现、验证、只读、计算属性
- 方法:实例方法、静态方法、虚方法、异步方法
- 索引器:类似数组访问的语法糖
- 事件:发布-订阅模式
- 继承:extends、base 关键字
- 模式匹配:is、as 运算符
练习
- 创建一个表示银行账户的类,包含余额属性和存取款方法
- 使用索引器创建一个类似数组的集合类
- 创建一个密封类并尝试继承,验证错误
- 使用记录类型创建一个不变的学生信息类型