Initial Obsidian notes backup
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
### 三大特性
|
||||
1. 封装
|
||||
2. 继承
|
||||
2. [[继承]]
|
||||
3. 多态
|
||||
|
||||
#### 七大原则
|
||||
|
||||
+23
-3
@@ -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;
|
||||
// }
|
||||
//}
|
||||
```
|
||||
|
||||
案例:
|
||||
原型在[[值类型和引用类型]]笔记中
|
||||
|
||||
|
||||
@@ -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 @@
|
||||
|
||||
注意:
|
||||
|
||||
|
||||
#封装
|
||||
#核心
|
||||
|
||||
|
||||
@@ -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):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();//等待回收完成
|
||||
```
|
||||
|
||||
|
||||
#封装
|
||||
#核心
|
||||
@@ -32,3 +32,5 @@ p[0] = new Person();
|
||||
```
|
||||
注意:
|
||||
|
||||
#封装
|
||||
#核心
|
||||
|
||||
@@ -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)
|
||||
|
||||
#继承
|
||||
#核心
|
||||
@@ -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. ==条件运算符需要成对实现==
|
||||
@@ -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. 只会==自动调用一次==
|
||||
@@ -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 [编程]
|
||||
设计一个可并发调用的计数器类,要求线程安全
|
||||
|
||||
**你的作答**
|
||||
(待填写)
|
||||
|
||||
**批改区**
|
||||
(待批改)
|
||||
Reference in New Issue
Block a user