C#知识学习-010(class)

 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.对比

特性

class

record

​类型​

引用类型(堆分配)

默认为引用类型(record class)
也可定义为值类型(record struct)

​可变性​

默认可变

默认不可变(init-only属性)

​相等性​

默认比较引用(内存地址)

默认比较值(所有属性内容)

​克隆/修改​

需手动实现

内置with表达式

​继承​

支持类的继承

只支持记录的继承

​用途​

封装数据+行为

不可变数据模型(如DTO、值对象)

学到了这里,咱俩真棒,记得按时吃饭(周五快乐噢!可以加餐~)

【本篇结束,新的知识会不定时补充】

感谢你的阅读!如果内容有帮助,欢迎 ​​点赞❤️ + 收藏⭐ + 关注​​ 支持! 😊

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值