本篇 核心知识点 :运算符重载、接口 interface、抽象类与接口核心区别、命名空间 namespace、预处理指令 (#define/#if/#endif 等)、正则表达式 Regex、异常处理 try-catch-finally-throw、自定义异常、装箱拆箱、特性 Attribute 基础
一、运算符重载
1. 概念
自定义类 / 结构体原本无法直接使用+ - * / == !=等运算符,通过operator关键字重载运算符,自定义运算逻辑,简化代码,替代冗余Add/Sub成员方法。
2. 核心规则
-
语法:
public static 返回类型 operator 运算符(参数列表),二元运算符需两个参数; -
只能重载 C# 允许的运算符,禁止重载
. ?: :: sizeof; -
相等
==与不等!=必须成对重载,否则编译警告; -
浮点数值判等不能直接用
==,需判断差值极小阈值; -
不改变运算符优先级、结合性、操作数数量。
3. 代码示例:二维向量 Point
class Point{
public float X, Y;
public Point(float x = 0, float y = 0){
X = x;
Y = y;
}
// 重载 + 向量相加
public static Point operator +(Point p1, Point p2) {
return new Point(p1.X + p2.X, p1.Y + p2.Y);
}
// 重载 - 向量相减
public static Point operator -(Point p1, Point p2){
return new Point(p1.X - p2.X, p1.Y - p2.Y);
}
// 重载 == 相等判断(浮点容错)
public static bool operator ==(Point p1, Point p2){
float eps = 1e-6f;
return Math.Abs(p1.X - p2.X) < eps && Math.Abs(p1.Y - p2.Y) < eps;
}
// 成对重载 !=
public static bool operator !=(Point p1, Point p2){
return !(p1 == p2);
}
public void Print(){
Console.WriteLine($"X:{X}, Y:{Y}");
}
}
// 测试
static void Main(){
Point a = new Point(2, 3);
Point b = new Point(1, 1);
Point c = a + b;
c.Print();
Console.WriteLine(a != b);
}
4. 拓展
1 向量
数字、向量
向量均可分别重载;
2 class 默认==比较堆内存地址,重载后实现值对比;
3 TS 无运算符重载,C++/C# 支持,游戏 Vector2/3 大量使用。
二、接口 interface
1. 概念
接口是一套行为规范契约,仅声明方法 / 属性,无实现;类 / 结构体实现接口,必须完整实现所有接口成员,用于多行为统一约束。
2. 核心特性
-
接口所有成员默认且只能是 public,不能写访问修饰符;
-
只能包含声明(方法、属性、事件),无字段、无构造函数;
-
不能实例化,仅能被子类实现;
-
C# 类单继承(仅一个父类) ,但可同时实现多个接口,弥补多继承缺失;
-
接口之间可多继承;
-
抽象类可写实现代码,接口全部为抽象无实现。
3. 抽象类 vs 接口(核心对比)
| 对比维度 | abstract 抽象类 | interface 接口 |
|---|---|---|
| 成员实现 | 可包含已实现普通方法、抽象方法 | 全部只有声明,无任何实现 |
| 构造函数 | 可写构造函数 | 无构造函数 |
| 继承规则 | 类只能继承一个抽象父类 | 一个类可实现 N 个接口 |
| 成员权限 | public/protected/private 均可 | 强制全部 public |
| 字段 | 可定义成员变量 | 不允许定义字段 |
| 使用场景 | 同类事物公共逻辑复用 | 不同事物统一行为标准(如点击、受伤) |
4. 代码示例
// 定义两个行为接口
interface IHit{
void TakeDamage(int atk); // 受伤害
}
interface IAnim{
void PlayIdle(); // 播放待机动画
}
// 植物类同时实现两个接口
class SunFlower : IHit, IAnim{
private int hp = 100;
// 实现接口受伤害方法
public void TakeDamage(int atk){
hp -= atk;
Console.WriteLine("向日葵受伤");
}
// 实现动画接口
public void PlayIdle(){
Console.WriteLine("播放向日葵待机动画");
}
static void Main(){
IHit plant = new SunFlower();
plant.Take(10); // 仅能调用接口定义方法
}
5. 实战拓展(Unity/Cocos)
UI 点击、拖拽、碰撞统一使用接口;引擎回调全部基于接口,只关心对象是否具备对应行为,不关心具体类型。
三、命名空间 namespace
1. 概念
相当于代码文件夹,隔离同名类,解决多文件、多库类名冲突问题。
2. 特性
-
语法:
namespace 名称 { 所有类/结构体 }; -
访问方式:
命名空间.类名; -
using 命名空间;简写,无需完整路径; -
支持多层嵌套(文件夹嵌套);
-
不同命名空间下同名类属于完全不同类型。
3. 代码示例
namespace Lesson7{
class Point { public int X; }
}
namespace Lesson8{
class Point { public float X; }
}
static void Main(){
// 完整路径区分同名类
Lesson7.Point p1 = new Lesson7();
Lesson8.Point p2 = new Lesson8();
}
拓展
Unity 大量命名空间区分引擎模块,冲突时必须写完整命名空间限定。
四、预处理指令 #define / #if / #endif
1. 概念
编译前执行的标记指令,不生成变量,仅定义符号,用于跨平台、Debug/Release 代码区分。
2. 核心指令
-
#define 符号名:定义编译标记,必须放在文件最顶部; -
#if / #elif / #else / #endif:判断标记是否存在,不存在代码直接不参与编译; -
#undef:取消已定义标记; -
#warning / #error:编译时抛出警告 / 错误; -
#region / #endregion:代码折叠块。
3. 特性
-
C# 预处理无 C++ 宏替换功能,仅做条件编译判断;
-
系统自带内置标记
DEBUG(调试模式自动定义); -
未定义符号区间代码灰色,编译直接忽略,不报错。
4 跨平台实战代码
#define IOS // 定义IOS平台标记
static void GameInit()
{
#if IOS
Console.WriteLine("IOS平台初始化");
#elif ANDROID
Console.WriteLine("安卓平台初始化");
#else
Console.WriteLine("Windows通用逻辑");
#endif
}
拓展
游戏跨平台生命周期、SDK 适配全部使用预处理区分;Release 模式DEBUG标记自动消失。
五、正则表达式 Regex
1. 概念
用于文本匹配、提取、校验字符串的规则模板,C# 内置System.Text.RegularExpressions.Regex类实现。
2. 常用元字符
\d 数字 0-9;\D 非数字
\w 字母数字下划线;\b 单词边界
+ 至少 1 次;* 0 或多次;? 0 或 1 次
{n} 精准匹配 n 次;[] 字符集
3. 基础代码示例(提取数字)
using System.Text.RegularExpressions;
static void TestRegex()
{
string str = "编号995 分数05";
// 匹配连续两位数字
Regex reg = new Regex(@"\d{2}");
MatchCollection mc = reg.Matches(str);
foreach(Match m in mc)
{
Console.WriteLine(m.Value);
}
}
实战场景
账号校验、配置文本解析、日志关键字提取。
六、异常处理 try-catch-finally-throw
1. 核心概念
程序运行错误称为异常,若不捕获会直接程序崩溃;通过try监控危险代码,catch捕获处理,finally无论是否异常必执行,throw主动抛出异常。
2 关键字分工
-
try:包裹可能报错的代码块; -
catch(异常类型 ex):捕获对应异常,可获取异常信息ex.Message; -
finally:无论正常 / 异常,代码一定会执行(释放资源专用); -
throw new Exception("提示"):手动抛出异常,向上层传递。
3. 基础示例(除数为零异常)
static float Div(float a, float b)
{
if (b == 0){
// 主动抛出异常
throw new Exception("除数不能为0");
}
return a / b;
}
static void Calc(){
float res = 0;
try {
res = Div(10, 0);
}
catch(Exception ex){
Console.WriteLine("捕获异常:" + ex.Message);
res = -1; // 异常默认值
}
finally{
Console.WriteLine("计算结束,释放临时资源");
}
Console.WriteLine("结果:" + res);
}
4. 自定义异常
概念
继承Exception自定义异常类,区分不同错误类型,精准分类捕获处理。
// 数组下限越界异常
class IndexLowException : Exception{
public IndexLowException(string msg) : base(msg) { }
}
// 数组上限越界异常
class IndexHighException : Exception{
public IndexHighException(string msg) : base(msg) { }
}
static void SetArr(int[] arr, int idx, int val){
if(idx < 0) throw new IndexLowException("下标小于0");
if(idx >= arr.Length) throw new IndexHighException("下标超出数组长度");
arr[idx] = val;
}
// 分层捕获
static void TestArr(){
int[] data = new int[5];
try{
SetArr(data, 8, 99);
}
catch(IndexLowException ex){
Console.WriteLine("下限错误:"+ex.Message);
}
catch(IndexHighException ex){
Console.WriteLine("上限错误:"+ex.Message);
}
}
拓展
1 无法处理的异常可再次throw向上抛给上层调用者;
2 文件、网络、数据库资源释放写在finally,保证资源关闭。
七、装箱 & 拆箱
1. 装箱(隐式)
值类型 → object 引用类型,栈数据拷贝到堆,自动完成。
int num = 10;
object obj = num; // 装箱
2. 拆箱(显式强制转换)
堆 object 转回栈值类型,必须强制转换,类型不匹配抛异常。
int res = (int)obj; // 拆箱
特性
频繁装箱拆箱产生大量堆临时对象,GC 压力大,高性能游戏尽量避免。
八、特性 Attribute(基础)
1. 概念
附加在类 / 方法 / 属性上的元数据标记,不影响程序运行,用于编译器提示、反射读取配置信息。
2. 系统内置常用特性
-
[Obsolete("提示文本", true)]标记弃用 API,true 编译报错,false 仅警告; -
[Conditional("DEBUG")]条件编译,仅定义标记时方法生效。
3. 自定义特性
继承Attribute实现自定义标记,存储开发备注、Bug 记录等元数据,通过反射读取。
代码示例(弃用特性)
[Obsolete("该方法已废弃,请使用CalcNew()", false)]
static void OldCalc(){
Console.WriteLine("旧计算逻辑");
}
九、反射前置
1. 概念
通过字符串类型名动态获取类、方法、属性信息,运行时创建对象、调用函数,依赖特性读取元数据。
核心 API
-
typeof(类)获取类型Type对象; -
Type.GetMethods()获取所有方法; -
Type.GetCustomAttributes()读取附加特性。
拓展
游戏热更新、配置表解析、框架插件系统底层全部基于反射。
十、拓展
1 接口与抽象类核心区分,多接口实现作用;
2 预处理指令作用,Debug/Release 区分原理;
3 异常三层结构 try-catch-finally 使用场景,自定义异常优势;
4 运算符重载成对规则、浮点判等坑;
5 特性本质元数据,反射读取流程;
6 装箱拆箱性能缺陷优化方案。