diff --git a/.vs/MyNotes/v17/.wsuo b/.vs/MyNotes/v17/.wsuo new file mode 100644 index 0000000..3834ea7 Binary files /dev/null and b/.vs/MyNotes/v17/.wsuo differ diff --git a/.vs/MyNotes/v17/DocumentLayout.json b/.vs/MyNotes/v17/DocumentLayout.json new file mode 100644 index 0000000..e749a28 --- /dev/null +++ b/.vs/MyNotes/v17/DocumentLayout.json @@ -0,0 +1,12 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\Users\\Kister\\OneDrive\\Apps\\remotely-save\\MyNotes\\", + "Documents": [], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [] + } + ] +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..5d1eeef Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/待办/CSharp重学.md b/待办/CSharp重学.md index 83a26b1..37cf25c 100644 --- a/待办/CSharp重学.md +++ b/待办/CSharp重学.md @@ -9,11 +9,13 @@ - [x] 变长参数 - [x] 结构体和枚举 - [x] 成员变量和访问修饰符 -- [ ] 垃圾回收 -- [ ] 成员属性 -- [ ] 索引器 -- [ ] 静态成员静态类和静态构造函数 -- [ ] 内部类和分布类 +- [x] 垃圾回收 +- [x] 成员属性 +- [x] 索引器 +- [x] 静态成员静态类和静态构造函数 +- [ ] 运算符重载 +- [x] 内部类和分部类 +- [x] 继承 - [ ] 装箱与拆箱 - [ ] 密封类 - [ ] 多态vob diff --git a/笔记/CSharp/基本概念.md b/笔记/CSharp/基本概念.md index 43e703a..8a64796 100644 --- a/笔记/CSharp/基本概念.md +++ b/笔记/CSharp/基本概念.md @@ -1,6 +1,6 @@ ### 三大特性 1. 封装 -2. 继承 +2. [[继承]] 3. 多态 #### 七大原则 diff --git a/笔记/CSharp/基础/ref和out.md b/笔记/CSharp/基础/ref和out.md index 7a27106..7ea079e 100644 --- a/笔记/CSharp/基础/ref和out.md +++ b/笔记/CSharp/基础/ref和out.md @@ -13,10 +13,30 @@ 在函数传参时,两边都要加上修饰词 ref: ```Csharp - static void ChangeValue(ref value) - ChangeValue(ref a); +//交换数字 + void Swap(ref int a, ref int b) + { + int temp = a; a = b; b = temp; + } +``` +out: +```Csharp +//最经典:int.TryParse +if (int.TryParse(Console.ReadLine(), out int value)) + Console.WriteLine(value % 2 == 0 ? "even" : "odd"); +//int.TryParse伪代码 +//bool ReadConfig(string key, out string value) +//{ +// if (配置存在) +// { +// value = 读取到的值; return true; +// } +// else +// { +// value = null; return false; +// } +//} ``` - 案例: 原型在[[值类型和引用类型]]笔记中 diff --git a/笔记/CSharp/核心/内部类和分部类.md b/笔记/CSharp/核心/内部类和分部类.md new file mode 100644 index 0000000..b4888d8 --- /dev/null +++ b/笔记/CSharp/核心/内部类和分部类.md @@ -0,0 +1,182 @@ +# 内部类 +概念: + 也叫==嵌套类== + 就是把一个类写在另一个类的内部 + 本质上它还是类,所以仍然是[[值类型和引用类型|引用类型]] + +通常用法: + 1. 给外部类当“小零件”用,不想单独暴露出去 + 2. 把关系很紧密的类型写在一起,减少命名污染 + 3. 配合[[成员变量和访问修饰符|访问修饰符]]控制谁能访问 + +语法: +```Csharp +class Outer +{ + public class Inner + { + + } +} +``` + +案例: +```Csharp +class Person +{ + private string name = "小明"; + + public class Pet + { + public void LookOwner(Person p) + { + cw(p.name); + } + } +} + +Person p = new Person(); +Person.Pet pet = new Person.Pet(); +pet.LookOwner(p); //输出 小明 +``` +↑ `Pet` 是 `Person` 的内部类,所以外部使用时一般写成 `Person.Pet` + +注意: +1. 更规范的说法一般是==嵌套类(nested class)== +2. ==类中的内部类如果不写访问修饰符,默认是private== +3. 外部访问时通常写 `外部类名.内部类名` +4. ==C# 的内部类不会自动绑定外部类对象==,想访问外部对象的数据,一般要把外部类对象传进去 +5. 内部类主要是为了==封装和组织代码==,不是继承 + +---- +# 分部类 +概念: + 在C#里更常见的叫法是==分部类== + 用 `partial` 关键字把==同一个类拆到多个文件或多个位置== + 编译时会把这些内容==合并成同一个类== + +通常用法: + 1. 一个类太长了,拆开写更清楚 + 2. 自动生成代码和手写逻辑分开 + 3. 多人协作时减少都挤在一个文件里的冲突 + +语法: +```Csharp +public partial class Player +{ + +} +``` +在另一个文件里也可以继续写: +```Csharp +public partial class Player +{ + +} +``` + +案例: +```Csharp +//Player_Base.cs +public partial class Player +{ + public string name; + + public void Move() + { + cw("移动"); + } +} + +//Player_Fight.cs +public partial class Player +{ + public int atk; + + public void Attack() + { + cw("攻击"); + } +} + +Player p = new Player(); +p.Move(); +p.Attack(); +cw(p.atk); +``` +↑虽然写在两个文件里,但编译后它们还是==同一个 `Player` 类== + +注意: +1. ==每一部分都要写 `partial`==,少一处都不行 +2. 一般要保证它们是==同名、同命名空间==的一组类型 +3. 分部类是==编译时合并==,不是继承,也不是复制出多个类 +4. 很适合配合工具自动生成代码,比如“工具生成一部分,自己手写一部分” +5. `partial` 不只类能用,结构体和接口也能用,但这节先记类 +6. 不要为了拆而拆,拆太碎反而更难找代码 + +---- +# 分部方法 +概念: + 分部方法就是写在==分部类==中的特殊方法 + 也是用 `partial` 关键字声明 + 一般是一边先声明“这里留个钩子”,另一边再决定要不要实现 + +通常用法: + 1. 给自动生成代码留扩展点 + 2. 把“框架流程”和“自定义逻辑”拆开 + 3. 某些逻辑可选,有需要时再补实现 + +语法: +先声明: +```Csharp +partial void OnCreated(); +``` +再在同一个分部类型的另一部分里实现: +```Csharp +partial void OnCreated() +{ + cw("创建完成"); +} +``` + +案例: +```Csharp +//Player_Base.cs +public partial class Player +{ + public Player() + { + OnCreated(); + } + + partial void OnCreated(); +} + +//Player_Extend.cs +public partial class Player +{ + partial void OnCreated() + { + cw("玩家初始化完成"); + } +} +``` +↑ 这种写法很适合“主逻辑在自动生成文件里,扩展逻辑在自己文件里” + +注意: +1. ==分部方法只能写在分部类型里==,普通类里不能单独这么用 +2. 它本质上是“声明部分”和“实现部分”配对 +3. 如果只是最经典那种可选分部方法,一般写法是==没有访问修饰符、返回 `void`、不能有 `out` 参数== +4. 这种“可选分部方法”如果没写实现,==编译器会把声明和调用一起移除== +5. ==如果你给它加了访问修饰符,或者返回值不是 `void`,通常就不能再省略实现== +6. 所以记忆上可以理解成:简单钩子可以不实现,复杂正式方法通常必须实现 + +---- +引用: +1. Microsoft Learn: [Nested types (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types) +2. Microsoft Learn: [Partial Classes and Members (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/partial-classes-and-methods) +3. Microsoft Learn: [partial type (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/partial-type) +4. Microsoft Learn: [Partial member (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/partial-member) + +#封装 +#核心 diff --git a/笔记/CSharp/核心/成员变量和访问修饰符.md b/笔记/CSharp/核心/成员变量和访问修饰符.md index 6a6be95..7ea8a66 100644 --- a/笔记/CSharp/核心/成员变量和访问修饰符.md +++ b/笔记/CSharp/核心/成员变量和访问修饰符.md @@ -49,3 +49,7 @@ 注意: + +#封装 +#核心 + diff --git a/笔记/CSharp/核心/成员属性.md b/笔记/CSharp/核心/成员属性.md index 7edfba3..578c197 100644 --- a/笔记/CSharp/核心/成员属性.md +++ b/笔记/CSharp/核心/成员属性.md @@ -69,6 +69,7 @@ p.Name = xxx; ↑最简单的防止money为负数的逻辑 注意: +==get必须有返回值== 成员属性不加访问修饰符,会使用成员变量声明时的访问权限 ==get和set也可以加访问修饰符,但是不能大于成员属性前访问修饰符的权限== 可以只有一个set或只有一个get(只能得或只能改),但是通常没人这么干 @@ -82,4 +83,8 @@ public float Height get; private set; } -``` \ No newline at end of file +``` + + +#封装 +#核心 diff --git a/笔记/CSharp/核心/构造函数、析构函数、垃圾回收.md b/笔记/CSharp/核心/构造函数、析构函数、垃圾回收.md new file mode 100644 index 0000000..8956f02 --- /dev/null +++ b/笔记/CSharp/核心/构造函数、析构函数、垃圾回收.md @@ -0,0 +1,245 @@ +# 构造函数: +概念: +实例化时,用于初始化的函数 +不写默认有一个无参构造函数 +==可以重载== + +通常用法: +自定义初始化规则 + +语法: +访问修饰符 类名(){} + +案例: +```Csharp +class Person() +{ + public string name; + public int age; + public Person() + { + name = "默认值"; + age = 默认值; + } +} +``` + +this关键字: + this指当前类声明的成员变量 +```Csharp + class Person() + { + public string name; + public int age; + public Person() + { + name = "默认值"; + age = 默认值; + } + public Person(int age,string name) //重构 + { + this.name = name; + //后面的name是传递的参数,this.name是最上方public int出来的 + this.age = name; + } + } +``` + +特殊写法: + 通过this重用构造函数代码,即先调用无参构造函数,然后在调用这个特殊写法的构造函数 + 语法:访问修饰符 构造函数名(参数列表):this(【可选】参数1,参数2.....) + 例子: +```Csharp + public Person(int age, string name):this(age) + { + balabala + } +``` + 过程:先调用无参Person构造函数,然后寻找只有构造单个参数age的构造函数进行初始化 + +注意: +==函数名和类名必须相同== +==没有特殊用途,一般都是public== + +==如果写了有参构造函数且自己没有保留无参构造函数,那么类在实例化时只能使用有参构造函数且无法使用无参构造函数== + + + +---- +# 析构函数 +概念: +当引用类型堆内存被回收时,会调用该函数 +对于需要手动管理内存的语言(C++),需要在析构函数中做一些内存回收处理 +C#有自动垃圾回收机制GC +Unity中基本不用管 + +通常用法: + + +语法: +```Csharp +~类名() +{ +} +``` +案例: +```Csharp +~Person() +{ + +} +``` + +注意: + + +---- +# 垃圾回收 +垃圾回收(GC) +通过遍历堆Heap上动态分配的所有对象 +通过识别他们是否被引用来确定哪些对象时垃圾,哪些对象仍然需要引用 +垃圾:没有变量或对象引用的内容 +如果是垃圾就要被回收释放 + +一般都是==被动触发(会造成卡顿)==,所以游戏一般需要手动执行垃圾回收 +语法:GC.Collect(); +==GC会造成卡顿,所以在加载Loading时一般会调用== + +垃圾回收有多种算法 +引用计数 +标记清楚 +标记整理 +复制集合 + +注意: +GC只负责Heap内存的垃圾祸首 +引用类型都是在Heap中的,所以他需要GC来进行管理 + +栈Stack上的内存时系统自动管理的 +所以不需要GC + +C#中垃圾回收机制的大概原理 +他会把内存分为0,1,2代内存 +代的概念是垃圾回收中的一种算法需要 +新分配的对象都会被配置在第0代内存中 +每次分配都可能会进行垃圾回收(一般来说0代内存满了就会触发) +在第一次内存回收过程开始时,垃圾回收器会认为堆中全是垃圾,会进行一下两部 +1.标记对象,从根(静态参数、方法参数)开始检查引用对象,标记后为可达对象,未标记就是不可大对象 +不可达对象就会认为是垃圾 +2.搬迁对象 压缩堆 (挂起执行内存托管代码线程:把第0代内存(还不是垃圾的内存)放到一代进行搬迁)释放未标记的对象、搬迁可达对象、修改引用地址 + +大对象总被认为是二带内存,目的是减少性能损耗 +不会对大对象进行压缩搬迁 大对象是85000kb以上的 + +示意图 +step1:程序放入内存 +![[Pasted image 20260412210327.png|697]] +step2:发现沾满了 +![[Pasted image 20260412210704.png]] +step3:原来的地址搬迁,无引用的垃圾丢掉 +![[Pasted image 20260412210810.png]] +step4:D放入 +![[Pasted image 20260412210946.png]] +step5:如果0代1代后续又满了,那么这套算法会同时做用在两代内存中,以此类推 +类似多级缓存cache,L1最快但常换L3最慢 +#基础 +# GC和IDispose() +### 首先区分资源类型: + +- **托管资源**:C# 自己管理的内存(比如普通对象、字符串) + - 不用你管,**垃圾回收器(GC)会自动释放** +- **非托管资源**:C# 管不了的外部资源 + - 例子:文件流、数据库连接、网络套接字、图片句柄、系统内核对象 + - **必须手动释放**,否则会造成**资源泄漏**(程序越跑越慢、卡死) + +### 为什么要用 `IDisposable`? + +- 非托管资源 GC 不会自动清理 +- 必须提供一个**标准、统一**的方式手动释放 +- `IDisposable` 就是 .NET 专门定义的**释放资源标准接口** + +### 标准释放模式 +例子: +```csharp +using System; + +// 1. 实现 IDisposable 接口 +public class MyResource : IDisposable +{ + // 标记资源是否已释放 + private bool _disposed = false; + + // 2. 公共释放方法(外部调用) + public void Dispose() + { + Dispose(true); + // 告诉GC:不用再管我了,我已经手动释放完了 + GC.SuppressFinalize(this); + } + + // 3. 核心释放逻辑 + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + // 释放 托管资源 + } + + // 释放 非托管资源(比如关闭文件、关闭数据库连接) + // 这里写你的资源释放代码 + + _disposed = true; + } + + // 4. 析构函数:防止用户忘记调用 Dispose + ~MyResource() + { + Dispose(false); + } +} +``` +##### 解释: +逻辑: + 1. 用完实例化对象 + 2. 调用`.Dispose()`手写的`.Close()`等方法进行手动释放 + 3. 判断标记变量 + 4. 没释放就执行释放代码 + 5. 标记为`true` + +`GC.SuppressFinalize(this);` 的作用 +告诉.NET的GC这个对象的非托管资源,我**手动释放完了**,你不需要在垃圾回收的时候,再执行它的析构函数了。==它不会取消GC运行,只是取消执行析构函数!== + + + +析构函数 `~MyResource()` 是干嘛的?和 GC 啥关系? +防止你忘记调用 `Dispose()` +场景模拟 +1. 你写了代码,**马虎忘了**调用 `.Dispose()` +2. 非托管资源(文件 / 数据库)一直占着没释放 +3. 等到 GC(清洁工)来回收垃圾时 +4. **自动触发析构函数** `~MyResource()` +5. 函数里执行 `Dispose(false)`,强行把非托管资源释放了 + + +==一个实例化对象dispose后就不会再用了(设计上就是如此,用过dispose后标签一直是true)== +==而且由于它dispose了,内部引用是空的,所以只会留下一个实例化的小壳== +==实例化的小壳也会因为没有被引用被GC清理,不会造成太大的性能问题== + +如果需要==一次性==彻底释放 +例子: +```Csharp +var resource1 = new MyResource(); +resource1.Dispose(); + +//手动切断引用 +resource1 = null; +//手动触发GC +GC.Collection(); +GC.WaitForPendingFinalizers();//等待回收完成 +``` + + +#封装 +#核心 diff --git a/笔记/CSharp/核心/索引器.md b/笔记/CSharp/核心/索引器.md index 63a4649..4c7a31f 100644 --- a/笔记/CSharp/核心/索引器.md +++ b/笔记/CSharp/核心/索引器.md @@ -32,3 +32,5 @@ p[0] = new Person(); ``` 注意: +#封装 +#核心 diff --git a/笔记/CSharp/核心/继承.md b/笔记/CSharp/核心/继承.md new file mode 100644 index 0000000..1035ee6 --- /dev/null +++ b/笔记/CSharp/核心/继承.md @@ -0,0 +1,143 @@ +# 继承 +概念: + 继承是面向对象三大特性之一 + 可以让一个类在已有类的基础上继续扩展 + 被继承的类一般叫==父类 / 基类(base class)== + 继承别人的类一般叫==子类 / 派生类(derived class)== + +通常用法: + 1. 提取多个类的共同内容,减少重复代码 + 2. 表达“==is-a==”关系 + 3. 让子类在父类基础上增加自己的成员和功能 + +语法: +```Csharp +class 子类名 : 父类名 +{ + +} +``` + +案例: +```Csharp +class Animal +{ + public string name; + protected int age; + + public Animal(string name) + { + this.name = name; + } + + public void Speak() + { + cw("动物发出声音"); + } +} + +class Dog : Animal +{ + public Dog(string name, int age) : base(name) + { + this.age = age; + } + + public void Bark() + { + cw(name); + cw(age); + cw("汪汪"); + } +} + +Dog d = new Dog("旺财", 3); +d.Speak(); +d.Bark(); +``` +↑ `Dog : Animal` 就表示 `Dog` 继承了 `Animal` + +注意: +1. ==C# 的类只能直接继承一个父类==,也就是单继承 +2. 继承是可以传递的,A 继承 B,B 继承 C,那么 A 也会继承到 C 的可用成员 +3. ==构造函数不会被继承==,子类只是可以调用父类构造函数 +4. 父类的 `private` 成员子类==不能直接访问==,想给子类用一般写 `protected` +5. 结构体 `struct` ==不支持继承类==,但可以实现接口 +6. 子类对象本质上也是父类对象的一种,所以继承是后面学[[多态vob|多态]]的基础 + +---- +# base关键字 +概念: + `base` 用来在==子类内部==访问父类成员 + 最常见的用途就是调用父类构造函数 + +通常用法: + 1. 在子类构造函数中调用父类构造函数 + 2. 在子类方法中访问父类同名成员或父类方法 + +语法: +```Csharp +class Dog : Animal +{ + public Dog(string name) : base(name) + { + + } +} +``` +调用父类成员: +```Csharp +base.父类成员名 +``` + +案例: +```Csharp +class Father +{ + public string name; + + public Father(string name) + { + this.name = name; + } + + public void Say() + { + cw("我是父类"); + } +} + +class Son : Father +{ + public Son(string name) : base(name) + { + + } + + public void Test() + { + base.Say(); + cw(base.name); + } +} + +Son s = new Son("小李"); +s.Test(); +``` +↑ `base(name)` 是先调用父类构造函数,`base.Say()` 是调用父类方法 + +注意: +1. `base` 只能在==实例构造函数、实例方法、实例属性访问器==里用 +2. ==静态方法里不能用 `base`== +3. 如果父类没有无参构造函数,子类通常就要显式写 `: base(...)` +4. `base` 是访问父类,不是创建一个新的父类对象 + +---- +引用: +1. Microsoft Learn: [Inheritance - derive types to create more specialized behavior](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/inheritance) +2. Microsoft Learn: [Inheritance in C# and .NET](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/inheritance) +3. Microsoft Learn: [base (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base) +4. Microsoft Learn: [protected (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected) + +#继承 +#核心 diff --git a/笔记/CSharp/核心/运算符重载.md b/笔记/CSharp/核心/运算符重载.md new file mode 100644 index 0000000..f7808b7 --- /dev/null +++ b/笔记/CSharp/核心/运算符重载.md @@ -0,0 +1,86 @@ +概念: +==让自定义类和结构体能够使用运算符== +让自定义类结构体可以进行运算 +通常需要注意运算符需要几个参数,例如取反只有一个参数,加有两个参数 + 可重载的运算符: + - 算数运算符 + - 逻辑运算符==非== + - 位运算符 + - 条件运算符 + 不可重载的运算符: + - 逻辑与(&&)逻辑或(||) + - 索引符\[] + - 墙砖运算符() + - 点. + - 三目运算符: ? + - 赋值符= + + +通常用法: + + +语法: +使用关键词operator +作为类的一个成员存在 +public static 返回值类型 operator 运算符(参数列表) + +案例: +```Csharp +class Point +{ + public int x; + public int y; + + public static Point operator +(Point p1, Point p2) + { + Point newPoint = new Point(); + newPoint.x = p1.x + p2.x; + newPoint.y = p1.y + p2.y; + + return newPoint; + } + + public static Point operator +(Point p1, int value) + { + Point newPoint = new Point(); + newPoint.x = p1.x + value; + newPoint.y = p1.y + value; + return newPoint; + } +} + +class Program +{ + public static void Main(string[] args) + { + Point p1 = new Point(); + p1.x = 1; + p1.y = 1; + + Point p2 = new Point(); + p2.x = 2; + p2.y = 2; + + Point p3 = new Point(); + p3 = p1 + p2; + Console.WriteLine(p3.x); + + p3 = null; + p3 = p1 + 10; + Console.WriteLine(p3.x); + } + +} +``` +第一个运算符重载了`+`号,可以让这个类的两个实例化对象相加 +第二个运算符也重载了`+`号,可以让这个类加上一个value +==如果需要value在前也需要进行一次重载!!!== + + +注意: +1. 一定是公共的静态方法 +2. 返回值写在operator前 +3. 逻辑处理自定义 +4. 一个符号可以多个重载 +5. 不能使用ref和out +6. ==条件运算符需要成对实现== diff --git a/笔记/CSharp/核心/静态成员.md b/笔记/CSharp/核心/静态成员.md new file mode 100644 index 0000000..7378cb0 --- /dev/null +++ b/笔记/CSharp/核心/静态成员.md @@ -0,0 +1,51 @@ +概念: +用static 修饰的成员变量、方法、属性 + +特点: +==直接用类名点出来使用 没有实例化!!!!== + +通常用法: +PI之类的全局且唯一性的 + +语法: +static 变量名 = XXX; + +案例: +```Csharp +class Test +{ + static public float PI = 3.1415926; //静态成员 + public int testInt = 100; + + public static float CalcCircle(float r) //静态方法 + { + return PI * r; + } + + public void TestFunc() //非静态方法 + { + Console.WriteLine("123"); + } +} + +static void Main(string[] args) +{ + Console.WriteLine(Test.PI); + Console.WriteLine(Test.CalcCircle(2)); +} +``` + +注意: +和程序同生共死,在程序使用后永远不会清除内存,直到程序结束 +非静态函数可以调用静态成员 +静态成员声明后可以不赋初始值 +静态方法中不能使用==没有实例化的==非静态成员 + + +[[常量]]可以理解为特殊的静态 +共同点 + - 都可以通过类名点出来使用 +不同点 + - const必须初始化,不能修改 static 没有这个限制 + - const值能修饰变量、static可以修饰很多 + - const一定是写在访问修饰符后面的,static没有这个要求 \ No newline at end of file diff --git a/笔记/CSharp/核心/静态类和静态构造函数.md b/笔记/CSharp/核心/静态类和静态构造函数.md new file mode 100644 index 0000000..747b8a9 --- /dev/null +++ b/笔记/CSharp/核心/静态类和静态构造函数.md @@ -0,0 +1,70 @@ +# 静态类 +概念: +用static修饰 +==只能包含静态成员== +==不能被实例化== + +通常用法: +作为==工具类==方便使用 + +语法: +访问修饰符 static 类名(){} + +案例: + ```Csharp + public static class fun() + { + + } + ``` + +注意: +静态类不能被实例化,所以不能new! + +# 静态构造函数 +概念: +staitc修饰 + +通常用法: +在静态函数中初始化静态变量 + +语法: + + +案例: +```Csharp +static class StaticClass +{ + public static int testInt = 100; + public static int testInt2 = 100; + + static StaticClass() + { + Console.WriteLine("静态构造函数"); + } +} +``` +↑运行后,在第一次使用该类会直接打印 +```Csharp +class Test +{ + public static int testInt = 200; + + static Test() + { + Console.WriteLine("静态构造函数"); + } + + + public Test() + { + Console.WriteLine("普通构造函数"); + } +} +``` +↑运行后,在第一次使用该类会在所有操作前先调用静态构造函数 +注意: +1. 静态类和普通类都可以用 +2. 不能使用访问修饰符 +3. ==不能有参数== +4. 只会==自动调用一次== diff --git a/笔记/CSharp/练习/CSharp复习题.md b/笔记/CSharp/练习/CSharp复习题.md new file mode 100644 index 0000000..a1abdc1 --- /dev/null +++ b/笔记/CSharp/练习/CSharp复习题.md @@ -0,0 +1,793 @@ +# CSharp 复习题库(分层练习) + +> 使用方式:每题都在“你的作答”填写答案;“批改区”由我批改后填写。 + +--- + +## 入门(16题) + +### 入门-1 [选择] +C# 源文件常见扩展名是:A. `.cs` B. `.csharp` C. `.dotnet` D. `.clr` + +**你的作答** +A + +**批改区** +- 结果:✅ 正确 +- 参考答案:A + +### 入门-2 [选择] +`Main` 方法作为入口,正确签名之一是:A. `void main()` B. `static void Main(string[] args)` C. `public Main()` D. `int Main(void)` + +**你的作答** +B + +**批改区** +- 结果:✅ 正确 +- 参考答案:B + +### 入门-3 [选择] +下列哪个是值类型:A. `string` B. `object` C. `int` D. `Array` + +**你的作答** +C + +**批改区** +- 结果:✅ 正确 +- 参考答案:C + +### 入门-4 [选择] +`var x = 10;` 中 `x` 的编译期类型是:A. `dynamic` B. `object` C. `int` D. `long` + +**你的作答** +C + +**批改区** +- 结果:✅ 正确 +- 参考答案:C + +### 入门-5 [选择] +输出到控制台应使用:A. `Console.ReadLine` B. `Console.WriteLine` C. `Console.Open` D. `Console.Print` + +**你的作答** +B + +**批改区** +- 结果:✅ 正确 +- 参考答案:B + +### 入门-6 [填空] +用于单行注释的符号是 `____` + +**你的作答** +`//` + +**批改区** +- 结果:✅ 正确 +- 参考答案:`//` + +### 入门-7 [填空] +`if` 条件表达式的结果类型必须是 `____` + +**你的作答** +`bool` + +**批改区** +- 结果:✅ 正确 +- 参考答案:`bool` + +### 入门-8 [填空] +将字符串 `"123"` 转 `int`,可用 `int.Parse("123")` 或 `____("123", out n)` + +**你的作答** +`Convert.Int32("123", out n)` + +**批改区** +- 结果:❌ 错误 +- 参考答案:`int.TryParse("123", out n)` +- 说明:`Convert.ToInt32` 没有 `out` 参数;带 `out` 的是 `TryParse`。 + +### 入门-9 [判断] +`const` 字段的值可以在运行时修改。对/错 + +**你的作答** +错 + +**批改区** +- 结果:✅ 正确 +- 参考答案:错 + +### 入门-10 [判断] +`string` 在 C# 中是引用类型。对/错 + +**你的作答** +对 + +**批改区** +- 结果:✅ 正确 +- 参考答案:对 + +### 入门-11 [代码结果] +写出输出: + +```csharp +int a = 5; +int b = 2; +Console.WriteLine(a / b); +Console.WriteLine(a / 2.0); +``` + +**你的作答** +`2` +`1.0` + +**批改区** +- 结果:❌ 错误 +- 参考答案: +```text +2 +2.5 +``` +- 说明:`a / b` 是整数除法,结果为 `2`。 + +### 入门-12 [代码改错] +修复下面代码使其可编译: + +```csharp +Console.Writeline("Hello") +``` + +**你的作答** +```csharp +Console.Writeline("Hello"); +``` + +**批改区** +- 结果:❌ 错误 +- 参考答案: +```csharp +Console.WriteLine("Hello"); +``` +- 说明:`WriteLine` 中 `L` 需要大写。 + +### 入门-13 [简答] +`==` 与 `Equals` 的常见区别是什么(1-2句话) + +**你的作答** +`Equals` 可以用于更复杂判断,`==` 只比较值。 + +**批改区** +- 结果:⚠️ 部分正确 +- 参考要点: + - `==` 是运算符,可被重载;不同类型语义可能不同。 + - `Equals` 是方法(实例/静态),常用于值相等判断。 + - 对 `string` 来说,`==` 比较的是内容(被重载),不是引用地址。 + +### 入门-14 [编程] +从控制台读取姓名和年龄,输出:`你好,张三,你明年 19 岁。` + +**你的作答** +```csharp +string name = Console.Readline(); +int age = int.Parse(Console.Readline()); +Console.WriteLine($"你好,{name},你明年 {age} 岁。"); +``` + +**批改区** +- 结果:❌ 错误 +- 参考答案: +```csharp +string name = Console.ReadLine(); +int age = int.Parse(Console.ReadLine()!); +Console.WriteLine($"你好,{name},你明年 {age + 1} 岁。"); +``` +- 说明:`ReadLine` 大小写错误,且“明年”应输出 `age + 1`。 + +### 入门-15 [编程] +输入一个整数,判断奇偶并输出 `odd/even` + +**你的作答** +```Csharp +int value = int.Parse(Console.ReadLine()); +if( value%2 != 0 ) +{ + Console.WriteLine("odd"); +} +else +{ + Console.WriteLine("even"); +} +``` + +**批改区** +- 结果:❌ 错误 +- 主要问题:`int.TryParse(...)` 返回 `bool`,不能直接赋给 `int` +- 参考答案: +```csharp +if (int.TryParse(Console.ReadLine(), out int value)) + Console.WriteLine(value % 2 == 0 ? "even" : "odd"); +``` + +### 入门-16 [编程] +输入三个整数,输出最大值 + +**你的作答** +```Csharp +int[] value; +int maxValue = 0; +value[0] = int.Parse(Console.ReadLine()); +value[1] = int.Parse(Console.ReadLine()); +value[2] = int.Parse(Console.ReadLine()); +for(int i = 0;i<2;i++) +{ + if(value[i]>=value[i+1]) + { + maxValue = value[i]; + } +} +Console.WriteLine(maxValue); +``` + +**批改区** +- 结果:❌ 错误 +- 主要问题:数组未初始化 +- 参考答案: +```csharp +int a = int.Parse(Console.ReadLine()!); +int b = int.Parse(Console.ReadLine()!); +int c = int.Parse(Console.ReadLine()!); +int maxValue = Math.Max(a, Math.Max(b, c)); +Console.WriteLine(maxValue); +``` + +--- +## 基础(18题) + +### 基础-1 [选择] +`for` 循环最适合:A. 已知次数迭代 B. 无限循环 C. 异常处理 D. 命名空间管理 + +**你的作答** +A + +**批改区** +- 结果:✅ 正确 +- 参考答案:A + +### 基础-2 [选择] +`break` 在循环中的作用是:A. 跳过本次 B. 结束当前循环 C. 结束程序 D. 重启循环 + +**你的作答** +B + +**批改区** +- 结果:✅ 正确 +- 参考答案:B + +### 基础-3 [选择] +`continue` 的作用是:A. 结束方法 B. 退出程序 C. 跳过本次迭代 D. 抛出异常 + +**你的作答** +C + +**批改区** +- 结果:✅ 正确 +- 参考答案:C + +### 基础-4 [选择] +数组声明正确的是:A. `int arr = new int[3]` B. `int[] arr = new int[3]` C. `array arr` D. `int arr[] = 3` + +**你的作答** +B + +**批改区** +- 结果:✅ 正确 +- 参考答案:B + +### 基础-5 [选择] +`List` 位于命名空间:A. `System.Text` B. `System.Collections.Generic` C. `System.Linq.Expressions` D. `System.IO` + +**你的作答** +B + +**批改区** +- 结果:✅ 正确 +- 参考答案:B + +### 基础-6 [填空] +定义一个可空整型变量:`int____ x = null;` + +**你的作答** +? + +**批改区** +- 结果:✅ 正确 +- 参考答案:`?` + +### 基础-7 [填空] +声明并初始化字典:`Dictionary d = new ____();` + +**你的作答** +`Dictionary + +**批改区** +- 结果:✅ 正确 +- 参考答案:`Dictionary` +- 说明:你填的类型名是对的,只是 Markdown 里的反引号没闭合。 + +### 基础-8 [填空] +捕获异常的关键字是 `____` + +**你的作答** +try和catch + +**批改区** +- 结果:⚠️ 部分正确 +- 参考答案:`catch` +- 说明:`try` 用来包裹可能抛异常的代码,真正负责捕获异常的是 `catch`。 + +### 基础-9 [填空] +释放非托管资源常用模式:实现 `____` 接口 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-10 [代码结果] +写出输出: + +```csharp +for (int i = 0; i < 5; i++) +{ + if (i == 2) continue; + if (i == 4) break; + Console.Write(i); +} +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-11 [代码结果] +写出输出: + +```csharp +string s = null; +Console.WriteLine(s?.Length ?? -1); +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-12 [改错] +找出并修复问题: + +```csharp +int[] nums = {1,2,3}; +Console.WriteLine(nums[3]); +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-13 [简答] +`throw;` 和 `throw ex;` 的差异是什么 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-14 [编程] +用 `while` 计算 `1..n` 的和(n 从输入读取) + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-15 [编程] +统计一个字符串中元音字母个数(忽略大小写) + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-16 [编程] +手写一个方法 `bool IsPrime(int n)` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-17 [编程] +使用 `List` 去重并升序输出 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 基础-18 [编程] +使用 `Dictionary` 统计一句话中每个单词出现次数 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +--- + +## 核心(18题) + +### 核心-1 [选择] +面向对象三大特性不包括:A. 封装 B. 继承 C. 多态 D. 事务 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-2 [选择] +`virtual` + `override` 用于:A. 字段隐藏 B. 运行时多态 C. 命名空间引用 D. 泛型约束 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-3 [选择] +`abstract` 类:A. 可直接实例化 B. 不能包含实现 C. 不能被继承 D. 不能直接实例化 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-4 [选择] +`interface` 成员默认:A. private B. protected C. public 合同 D. internal + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-5 [选择] +泛型约束 `where T : class` 的含义是:A. 值类型 B. 引用类型 C. 必须有无参构造 D. 必须实现 IDisposable + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-6 [填空] +声明一个自动属性:`public int Age { ____; ____; }` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-7 [填空] +只读自动属性常见写法:`public string Id { get; ____; }` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-8 [填空] +委托声明关键字是 `____` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-9 [填空] +事件订阅语法:`publisher.SomeEvent ____ Handler;` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-10 [代码阅读] +输出是什么: + +```csharp +class A { public virtual void M() => Console.Write("A"); } +class B : A { public override void M() => Console.Write("B"); } +A x = new B(); +x.M(); +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-11 [代码阅读] +输出是什么: + +```csharp +int Add(int a, int b = 10) => a + b; +Console.WriteLine(Add(5)); +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-12 [改错] +指出并修复: + +```csharp +interface IRun { void Go() { Console.WriteLine("go"); } } +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-13 [简答] +`override` 与 `new` 隐藏成员的行为区别 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-14 [简答] +什么时候用接口,什么时候用抽象类(简述判断标准) + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-15 [编程] +设计 `Shape` 抽象类,派生 `Circle/Rectangle`,实现 `GetArea()` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-16 [编程] +实现泛型方法 `Swap(ref T a, ref T b)` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-17 [编程] +定义一个 `event EventHandler`,在数据变化时触发 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 核心-18 [编程] +实现一个只读集合包装(对外不可修改,内部可维护) + +**你的作答** +(待填写) + +**批改区** +(待批改) + +--- + +## 进阶(18题) + +### 进阶-1 [选择] +`async/await` 中,`await` 作用是:A. 创建线程 B. 异步等待任务完成 C. 阻塞 UI 线程 D. 强制并行 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-2 [选择] +表示“一个无返回值异步操作”的常用返回类型:A. `void` B. `Task` C. `object` D. `Result` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-3 [选择] +LINQ 中用于投影的操作符:A. `Where` B. `Select` C. `Any` D. `Count` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-4 [选择] +延迟执行是 LINQ 的常见特性之一,以下通常会立即执行的是:A. `Where` B. `Select` C. `ToList` D. `OrderBy` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-5 [选择] +`using` 语句主要用于:A. 导入命名空间 B. 自动释放资源 C. 定义别名 D. 启动任务 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-6 [填空] +声明取消令牌源:`var cts = new ____();` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-7 [填空] +正则匹配常用类型:`System.Text.RegularExpressions.____` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-8 [填空] +线程安全递增可用:`Interlocked.____(ref x);` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-9 [填空] +文件全部文本读取:`File.____(path)` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-10 [代码结果] +写出输出: + +```csharp +var nums = new[] {1,2,3,4,5}; +var q = nums.Where(x => x % 2 == 1).Select(x => x * x); +Console.WriteLine(string.Join(",", q)); +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-11 [代码结果] +判断是否死锁风险并说明一句原因: + +```csharp +Task.Run(async () => { await Task.Delay(100); }).Wait(); +``` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-12 [简答] +`Task.WhenAll` 与顺序 `await` 的区别 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-13 [简答] +`IEnumerable` 与 `IQueryable` 的核心差异 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-14 [编程] +异步读取文本文件并统计行数,支持取消(`CancellationToken`) + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-15 [编程] +用 LINQ 完成:给定学生列表,按班级分组后求每组平均分并降序输出 + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-16 [编程] +实现一个简单缓存 `MemoryCache`(带过期时间) + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-17 [编程] +写一个扩展方法 `IsNullOrEmptyEx(this string? s)` + +**你的作答** +(待填写) + +**批改区** +(待批改) + +### 进阶-18 [编程] +设计一个可并发调用的计数器类,要求线程安全 + +**你的作答** +(待填写) + +**批改区** +(待批改) diff --git a/笔记/CSharp笔记汇总.md b/笔记/CSharp笔记汇总.md index afdd88b..0c9dfdf 100644 --- a/笔记/CSharp笔记汇总.md +++ b/笔记/CSharp笔记汇总.md @@ -13,19 +13,21 @@ 5. [[结构体]]和[[枚举]] # 核心 1. [[成员变量和访问修饰符]] -2. [[构造、解析、垃圾回收]] +2. [[构造函数、析构函数、垃圾回收]] 3. [[成员属性]] 4. [[索引器]] -5. 静态成员静态类和静态构造函数 -6. 内部类和分布类 -7. 装箱与拆箱 -8. 密封类 -9. 多态vob -10. 抽象类和抽象函数 -11. 接口 -12. 密封函数 -13. 命名空间 -14. 抽象类的接口的区别 +5. [[静态成员]],[[静态类和静态构造函数]] +6. [[运算符重载]] +7. [[内部类和分部类]] +8. [[继承]] +9. 装箱与拆箱 +10. 密封类 +11. 多态vob +12. 抽象类和抽象函数 +13. 接口 +14. 密封函数 +15. 命名空间 +16. 抽象类的接口的区别 # 进阶 1. ArrayList 2. Stack @@ -43,4 +45,4 @@ 14. 协变逆变 15. 多线程 16. 预处理器 -17. 反射 \ No newline at end of file +17. 反射