Initial Obsidian notes backup

This commit is contained in:
2026-06-18 20:01:30 +08:00
parent 02810617db
commit ebb9e385c5
17 changed files with 1639 additions and 22 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
### 三大特性
1. 封装
2. 继承
2. [[继承]]
3. 多态
#### 七大原则
+23 -3
View File
@@ -13,10 +13,30 @@
在函数传参时,两边都要加上修饰词
ref
```Csharp
static void ChangeValueref value
ChangeValueref 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;
// }
//}
```
案例:
原型在[[值类型和引用类型]]笔记中
@@ -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)
#封装
#核心
@@ -49,3 +49,7 @@
注意:
#封装
#核心
+6 -1
View File
@@ -69,6 +69,7 @@ p.Name = xxx
↑最简单的防止money为负数的逻辑
注意:
==get必须有返回值==
成员属性不加访问修饰符,会使用成员变量声明时的访问权限
==get和set也可以加访问修饰符,但是不能大于成员属性前访问修饰符的权限==
可以只有一个set或只有一个get(只能得或只能改),但是通常没人这么干
@@ -82,4 +83,8 @@ public float Height
get;
private set;
}
```
```
#封装
#核心
@@ -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)thisage
{
balabala
}
```
过程:先调用无参Person构造函数,然后寻找只有构造单个参数age的构造函数进行初始化
注意:
==函数名和类名必须相同==
==没有特殊用途,一般都是public==
==如果写了有参构造函数且自己没有保留无参构造函数,那么类在实例化时只能使用有参构造函数且无法使用无参构造函数==
----
# 析构函数
概念:
当引用类型堆内存被回收时,会调用该函数
对于需要手动管理内存的语言(C++),需要在析构函数中做一些内存回收处理
C#有自动垃圾回收机制GC
Unity中基本不用管
通常用法:
语法:
```Csharp
~
{
}
```
案例:
```Csharp
~Person
{
}
```
注意:
----
# 垃圾回收
垃圾回收(GC
通过遍历堆Heap上动态分配的所有对象
通过识别他们是否被引用来确定哪些对象时垃圾,哪些对象仍然需要引用
垃圾:没有变量或对象引用的内容
如果是垃圾就要被回收释放
一般都是==被动触发(会造成卡顿)==,所以游戏一般需要手动执行垃圾回收
语法:GC.Collect();
==GC会造成卡顿,所以在加载Loading时一般会调用==
垃圾回收有多种算法
引用计数
标记清楚
标记整理
复制集合
注意:
GC只负责Heap内存的垃圾祸首
引用类型都是在Heap中的,所以他需要GC来进行管理
栈Stack上的内存时系统自动管理的
所以不需要GC
C#中垃圾回收机制的大概原理
他会把内存分为012代内存
代的概念是垃圾回收中的一种算法需要
新分配的对象都会被配置在第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();//等待回收完成
```
#封装
#核心
+2
View File
@@ -32,3 +32,5 @@ p[0] = new Person();
```
注意:
#封装
#核心
+143
View File
@@ -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)
#继承
#核心
+86
View File
@@ -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. ==条件运算符需要成对实现==
+51
View File
@@ -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没有这个要求
@@ -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. 只会==自动调用一次==
+793
View File
@@ -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<int> arr` D. `int arr[] = 3`
**你的作答**
B
**批改区**
- 结果:✅ 正确
- 参考答案:B
### 基础-5 [选择]
`List<T>` 位于命名空间:A. `System.Text` B. `System.Collections.Generic` C. `System.Linq.Expressions` D. `System.IO`
**你的作答**
B
**批改区**
- 结果:✅ 正确
- 参考答案:B
### 基础-6 [填空]
定义一个可空整型变量:`int____ x = null;`
**你的作答**
?
**批改区**
- 结果:✅ 正确
- 参考答案:`?`
### 基础-7 [填空]
声明并初始化字典:`Dictionary<string,int> d = new ____();`
**你的作答**
`Dictionary<string,int>
**批改区**
- 结果:✅ 正确
- 参考答案:`Dictionary<string,int>`
- 说明:你填的类型名是对的,只是 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<int>` 去重并升序输出
**你的作答**
(待填写)
**批改区**
(待批改)
### 基础-18 [编程]
使用 `Dictionary<string,int>` 统计一句话中每个单词出现次数
**你的作答**
(待填写)
**批改区**
(待批改)
---
## 核心(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<T>(ref T a, ref T b)`
**你的作答**
(待填写)
**批改区**
(待批改)
### 核心-17 [编程]
定义一个 `event EventHandler<DataEventArgs>`,在数据变化时触发
**你的作答**
(待填写)
**批改区**
(待批改)
### 核心-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<T>` 与 `IQueryable<T>` 的核心差异
**你的作答**
(待填写)
**批改区**
(待批改)
### 进阶-14 [编程]
异步读取文本文件并统计行数,支持取消(`CancellationToken`
**你的作答**
(待填写)
**批改区**
(待批改)
### 进阶-15 [编程]
用 LINQ 完成:给定学生列表,按班级分组后求每组平均分并降序输出
**你的作答**
(待填写)
**批改区**
(待批改)
### 进阶-16 [编程]
实现一个简单缓存 `MemoryCache<TKey,TValue>`(带过期时间)
**你的作答**
(待填写)
**批改区**
(待批改)
### 进阶-17 [编程]
写一个扩展方法 `IsNullOrEmptyEx(this string? s)`
**你的作答**
(待填写)
**批改区**
(待批改)
### 进阶-18 [编程]
设计一个可并发调用的计数器类,要求线程安全
**你的作答**
(待填写)
**批改区**
(待批改)
+14 -12
View File
@@ -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. 反射
17. 反射