1.class
类是使用关键字 class声明的,如以下示例所示:
class TestClass
{
.....
}
1.1 定义
类是C#中最基本的类型之一,用于封装数据和行为(方法、属性、事件等)。类支持面向对象编程的四大特性:封装、继承、多态和抽象。(先了解即可,后续会讲)
1.2 特点
-
引用类型:存储在堆中,赋值时传递引用(复制内存地址)。
-
举例:
// 示例 var book1 = new Book { Title = "C# Basics" }; var book2 = book1; // 传递内存地址(非创建新对象) book2.Title = "Advanced C#"; Console.WriteLine(book1.Title); // 输出: Advanced C#(修改同一内存地址) Console.WriteLine(ReferenceEquals(book1, book2)); // 输出: True(同一对象) public class Book { public string Title { get; set; } } -
可变性:默认支持修改属性值(除非标记为
readonly)。 -
举例:
// 示例 var cart = new ShoppingCart { ItemCount = 3 }; cart.AddItem(); cart.ItemCount = 5; // 直接修改属性 Console.WriteLine(cart.ItemCount); // 输出: 5 public class ShoppingCart { public int ItemCount { get; set; } // 默认可修改属性 public void AddItem() { ItemCount++; } } -
相等性:默认基于引用比较(两个变量是否指向同一个内存地址)。
-
举例:
// 示例 var point1 = new Coordinate { X = 10, Y = 20 }; var point2 = new Coordinate { X = 10, Y = 20 }; // 即使属性值相同,也返回False(比较内存地址) Console.WriteLine(point1 == point2); // 输出: False // 改为指向同一对象 point2 = point1; Console.WriteLine(point1 == point2); // 输出: True public class Coordinate { public int X { get; set; } public int Y { get; set; } } -
核心用途:封装数据+行为(如方法、事件等),面向对象编程的基石。
-
举例:
public class Child { private int age; // Private field (数据) private string name; // Private field (数据) // Default constructor (行为 - 构造) public Child() { name = "bo luo"; } // Parameterized constructor (行为 - 构造) public Child(string name, int age) { this.name = name; // 'this' refers to the current object this.age = age; } // Method (行为 - 操作) public void PrintChild() { Console.WriteLine("{0}, {1} years old.", name, age); } }
1.3 类和成员的访问修饰符
1.3.1 类本身的访问级别
直接在命名空间中声明的类(而不是嵌套在其他类中)可以是 公共 类,也可以是 内部类。
public class Dog { } // 公共类 - 任何项目都可访问
internal class Cat { } // 内部类 - 仅当前项目可见(默认)
1.3.2 类成员的访问级别
类成员(包括嵌套类)可以是 公共、 受保护的内部、 受保护、 内部、 私有或 专用保护。
public class Animal
{
public string Cat { get; } // 公共成员
private int Num; // 私有成员
protected int Count; // 受保护成员
internal string Dog; // 内部成员
protected internal int CatNum; // 受保护的内部成员
private protected string dogName; // 私有保护成员
}
1.3.3 嵌套类
// 外部使用
var bobo = new Animal.Pig(); // public 嵌套类可外部访问
public class Animal
{
private class Cat { } // 私有的嵌套类
protected class Dog { } // 受保护的嵌套类
public class Pig { } // 公共的嵌套类
public void Book()
{
var mb = new Pig(); // 外部类可访问所有嵌套类
}
}
1.4 类的继承
核心原则:
- 类只能继承一个父类(单一继承)
- 类可以实现多个接口(无数量限制)
1.4.1 不继承任何东西
这是个独立类, 没有继承任何类,没有实现任何接口
class ClassA { }
1.4.2 继承一个父类
继承了ClassA,没有实现接口
-
语法要点:冒号后只跟了一个类名
class ClassB : ClassA { }
1.4.3 实现多个接口(无继承)
没有继承类,实现了两个接口(IFace1和IFace2),(先了解即可,后续会讲接口)
-
语法要点:冒号后跟着接口名,用逗号分隔
class ClassA : IFace1, IFace2 { }
1.4.4 继承父类+实现接口
继承了ClassA,实现了IFace1接口
-
语法要点:先写父类名,再写接口名
class ClassB : ClassA, IFace1 { }
2.record
在 C# 9.0 及更高版本中,record是一种特殊的引用类型,专门设计用于封装不可变数据模型。它简化了值比较、克隆和模式匹配等操作,特别适合 DTO(数据传输对象)、领域模型和不可变数据结构。
-
分为两种形式:
-
record class:引用类型(可简写为record) -
record struct:值类型
-
举例:
// 引用类型记录
public record Person
{
public required string FirstName { get; init; } // 只读
public required string LastName { get; init; }
}
// 值类型记录
public record struct Point
{
public double X { get; init; } // 只读
public double Y { get; init; }
}
两者的区别:
// RECORD CLASS (引用类型)
public record RPerson(string Name, int Age);
// RECORD STRUCT (值类型)
public record struct SPerson(string Name, int Age);
// 测试
var rc = new RPerson("Alice", 30);
// rc.Name = "Bob"; // 错误!Name 是只读的
var rs = new SPerson("Alice", 30);
rs.Name = "Bob"; // 有效!可以修改
var rc1 = new RPerson("Alice", 30);
var rc2 = rc1; // 传递引用(指向同一对象)
var rs1 = new SPerson("Alice", 30);
var rs2 = rs1; // 传递值(复制整个对象)
rs1.Name = "Bob";
Console.WriteLine(rc1 == rc2); // true(同一引用)
Console.WriteLine(rs1 == rs2); // false(内容不同)
2.1 值语义的相等性
public record Person(string Name, int Age);
var person1 = new Person("bo luo", 1);
var person2 = new Person("bo luo", 1);
Console.WriteLine(person1 == person2); // 输出 True
-
自动实现值比较:比较所有属性值(而非引用地址)。
-
自动重写
Equals()、GetHashCode()和==/!=运算符。
2.2 非破坏性修改(with表达式)
var person3 = person1 with { Age = 2 };
Console.WriteLine(person3); // 输出 Person { Name = bo luo, Age = 2 }
2.3 不可变性
public record Person
{
public string Name { get; init; } // init 只能在构造时设置
public int Age { get; init; } // 后续不能修改
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
var person = new Person("Alice", 30);
// person.Age = 31; // 错误:init-only 属性无法修改
2.3 继承
📌 核心规则:记录只能继承记录
public record Animal(string Name); // 基记录
public record Dog(string Name) : Animal; // 继承 ✅
public record Cat(string Name) : Animal; // 继承 ✅
// 以下均无效
public record Bird : Animal; // ❌ 必须提供基类的参数
public class Human : Animal {} // ❌ 类不能继承记录
public record Fish : object {} // ❌ 记录不能继承类
补充:派生记录必须满足基记录的构造要求:
编译器要求派生记录Bird必须:
-
在自己的位置参数列表中包含基类的所有参数
-
在继承声明中将参数传递给基类构造函数
3.对比
|
特性 |
|
|
|---|---|---|
|
类型 |
引用类型(堆分配) |
默认为引用类型( |
|
可变性 |
默认可变 |
默认不可变( |
|
相等性 |
默认比较引用(内存地址) |
默认比较值(所有属性内容) |
|
克隆/修改 |
需手动实现 |
内置 |
|
继承 |
支持类的继承 |
只支持记录的继承 |
|
用途 |
封装数据+行为 |
不可变数据模型(如DTO、值对象) |
学到了这里,咱俩真棒,记得按时吃饭(周五快乐噢!可以加餐~)
【本篇结束,新的知识会不定时补充】
感谢你的阅读!如果内容有帮助,欢迎 点赞❤️ + 收藏⭐ + 关注 支持! 😊
416

被折叠的 条评论
为什么被折叠?



