C#基础入门与面向对象编程学习总结

📅 2026/7/27 6:09:55 👁️ 阅读次数 📝 编程学习
C#基础入门与面向对象编程学习总结

从零开始学 C#,跟着课程一天天往后推,从基础语法到面向对象。难度慢慢上来,有时候反复查资料,边练边理解。这篇文章是这两周学习的总结和备忘。


一、C# 和 .NET 的关系

刚开始确实没搞明白。后来弄清楚了:C# 是语言,.NET 是运行平台。就像写字需要纸和笔,C# 是笔,.NET 是纸。现在主要分两种:

  • .NET Framework:老版本,只能在 Windows 上跑,基本是旧项目维护在用。
  • .NET(.NET Core / .NET 5+):微软主推的跨平台版本,Windows、Linux、macOS 都能跑,性能也更好。

我们课程用的是 .NET 8,新项目直接选这个就行。


二、基础语法

2.1 变量和数据类型

C# 是强类型语言,声明变量必须明确指定类型,所有变量必须先定义后使用。这和 JavaScript、Python 那些弱类型语言不一样,一开始觉得有点"死板",但后面理解了——不同类型内存占用不同,提前确定类型能提高效率。

常用数据类型
类型关键字字节范围说明
字节sbyte1-128~127有符号
短整数short2-32768~32767
整数int4±21亿最常用
长整数long8±9×10¹⁸后面加 L
浮点数float47位精度后面加 F
双精度double815-16位精度小数默认
高精度decimal1628-29位精度后面加 M
布尔bool1true/false
字符char20~65535单引号,一个字符
字符串string--双引号,任意长度

注意点:

  • 整数默认是 int 类型,小数默认是 double 类型
  • float 必须加 F(如1.2F),decimal 必须加 M(如5.5M
  • char 本质也是整数类型,每个字符对应一个 Unicode 编码
  • 字符串可以和 + 拼接,也可以用$插值格式化输出
const 和 readonly

区别不大但面试经常问到:

constreadonly
初始化时机声明时必须赋值声明时或构造函数中
值确定时间编译时运行时
类型限制只能是基本类型或 string可以是任何类型
静态性隐式静态可以是实例或静态

记住:const 编译时定死,readonly 运行时确定,更灵活。

类型转换
// 自动转换:小范围 → 大范围doublenum=10;// int 自动转 double// 强制转换:大范围 → 小范围(可能丢精度)doublenum1=5.5;intnum2=(int)num1;// 输出 5,小数位直接舍弃// Parse 转换:string → 其他类型inta=int.Parse("100");doubleb=double.Parse("3.14");// Convert 转换:通用strings=Convert.ToString(99);inti=Convert.ToInt32(3.14);// 四舍五入

2.2 C# 关键字

关键字是 C# 预留的标识符,有特殊含义,不能用作变量名或类名。VS 里关键字默认蓝色显示。学习中常见的:

using、namespace、class、static、void、int、string、bool、if、else、 switch、case、for、while、do、new、return、this、base、public、private、 protected、virtual、override、abstract、const、readonly、out、ref

不需要死记,写得多了自然就熟了。如果非要用关键字做变量名,前面加@,比如@if,但一般不这么干。

2.3 注释

// 单行注释/* 多行注释 *//// <summary>/// XML 文档注释,写在方法/类前面/// </summary>/// <param name="a">参数说明</param>/// <returns>返回值说明</returns>

XML 文档注释在 VS 里调用方法时会自动提示,写公共方法的时候很有用。

2.4 流程控制

刚开始学循环觉得挺难的,后面写多了也就习惯了:

  • for:明确知道循环次数用这个,常用于遍历数组
  • while:知道条件但不清楚具体次数,或者无限循环
  • do-while:不管怎样先跑一轮再判断
if-else 和 switch
// if-else:用于区间判断if(score>=90){Console.WriteLine("A");}elseif(score>=60){Console.WriteLine("B");}else{Console.WriteLine("C");}// switch:用于值的一一对应switch(choice){case0:Console.WriteLine("包子");break;case1:Console.WriteLine("米粉");break;default:Console.WriteLine("不合法");break;}

switch 的变量可以是 byte、short、int、char、string、枚举类型。每个 case 后面必须加 break。if-else 适合区间判断,switch 适合离散值的匹配。

2.5 数组

内存里一块连续的空间,用来存放同类型的多个数据。它是引用类型,变量名存的是堆内存地址,不是数据本身。所以两个变量指向同一个数组时,改一个另一个也跟着变——因为指向同一块内存。

数组的两种初始化
// 动态初始化:先定长度,系统给默认值int[]arr=newint[5];// {0,0,0,0,0}// 静态初始化:创建时直接放值int[]arr2={1,3,5,7,9};int[]arr3=newint[]{1,3,5,7,9};

默认值规律:整数型=0,浮点型=0.0,char=空字符,string=null,bool=false。

常用操作
int[]arr={3,1,4,1,5};// 获取长度intlen=arr.Length;// 5// for 遍历for(inti=0;i<arr.Length;i++){Console.WriteLine(arr[i]);}// foreach 遍历foreach(intninarr){Console.WriteLine(n);}// 系统方法Array.Sort(arr);// 排序Array.Reverse(arr);// 反转intidx=Array.IndexOf(arr,4);// 查找索引Array.Copy(arr,newArr,arr.Length);// 复制
常见异常
  • IndexOutOfRangeException:下标越界,访问了不存在的索引
  • NullReferenceException:数组没初始化(null)就去访问元素
二维数组
// 矩形数组:每行等长int[,]arr=newint[2,3]{{1,2,3},{4,5,6}};// arr.GetLength(0) → 行数,arr.GetLength(1) → 列数// 锯齿数组:每行长度可以不同int[][]jagged=newint[3][];jagged[0]=newint[2];jagged[1]=newint[3];jagged[2]=newint[1];

2.6 字符串操作

字符串是 string 类型,属于引用类型,用双引号括起来。以下方法在作业里反复用到:

strings="hello@163.com";// 属性s.Length;// 获取字符串长度// 查找s.IndexOf("@");// 查找第一个 @ 的位置,找不到返回 -1s.LastIndexOf(".");// 查找最后一个 . 的位置// 截取s.Substring(0,5);// 从 0 开始截 5 个字符 → "hello"s.Substring(6);// 从 6 开始截到末尾 → "163.com"// 分割和拼接string[]parts=s.Split('@');// 按 @ 拆 → {"hello", "163.com"}string.Join("-",new[]{"a","b","c"});// 用 - 拼接 → "a-b-c"// 大小写s.ToUpper();// 转大写s.ToLower();// 转小写// 比较s1.Equals(s2);// 判断两个字符串内容是否相等// 格式化string.Format("姓名:{0},年龄:{1}",name,age);// 占位符替换// 去除空白s.Trim();// 去掉首尾空格

这些方法处理邮箱截取、IP 拆分、用户名提取这类需求时很常用。

2.7 方法

把重复代码封装进方法里,调用就行不用每次重写。方法格式:

[public] static 返回值类型 方法名(参数列表) { 方法体; return 返回值; // void 则不需要 }

四种分类:无参无返、无参有返、有参无返、有参有返。

参数传递要点:

  • 值类型传的是副本,方法内改了不影响外面
  • 引用类型传的是地址,方法内改了外面跟着变
  • out 参数:可以在方法内返回多个值,调用前不需要初始化
  • ref 参数:双向传递,调用前必须初始化

方法重载:同一个类中,方法名相同,参数列表不同(个数、类型、顺序),与返回值无关。


三、面向对象

3.1 面向过程 vs 面向对象

这是编程思想的转变。

  • 面向过程:关注"怎么做",一步步执行动作。比如把大象塞进冰箱——开门→塞象→关门。
  • 面向对象:关注"谁来做",把事物抽象成对象,由对象之间配合完成。冰箱有开门和关门的行为,大象是一个对象。

面向对象的核心优势:写出通用代码,屏蔽差异。张三踩板凳开门和王五直接开门,在面向对象中都可以抽象为"门.打开()"。

3.2 类和对象

类是模板,对象是实例。类不占内存,new 出来的对象才占内存。

classPerson{// 字段(私有)privatestring_name;privateint_age;// 属性(对外暴露)publicstringName{get{return_name;}set{_name=value;}}publicintAge{get{return_age;}set{if(value<0||value>120)value=0;_age=value;}}// 方法publicvoidShow(){Console.WriteLine($"我叫{Name},今年{Age}岁");}}

3.3 封装

字段用 private 藏起来,外面通过属性 get/set 访问。属性的好处是可以在里面加校验逻辑——比如年龄不能为负、性别只能是男女。这些校验写在属性里,比散落在外面的代码安全得多。

3.4 构造方法

名字和类名一样,没有返回值(连 void 都不写),new 对象时自动调用。写了有参构造后默认无参会失效,建议两个都写上。this 用于构造函数之间互相调用:

publicPerson(){}publicPerson(stringname,intage):this(name,age,'男',0,0,0){}publicPerson(stringname,intage,charsex,intchinese,intenglish,intmath){this.Name=name;this.Age=age;this.Sex=sex;this.Chinese=chinese;this.English=english;this.Math=math;}

3.5 访问修饰符

修饰符同类中子类中外部类
private××
protected×
public

默认规范:字段用 private,需要给子类用的用 protected,对外暴露的方法和属性用 public。

3.6 继承

子类: 父类就能使用父类的非私有成员。C# 是单继承,一个类只能有一个直接父类,但支持多层继承(传递性:子类→父类→爷类)。

classDog:Animal{publicDog(stringn,doublew):base(n,w){}// 调用父类构造publicoverridevoidEat(){Console.WriteLine("肉真好吃");}}

关键点:

  • 子类不继承父类的构造函数,但创建子类对象时会默认调用父类的无参构造
  • base 关键字用于访问父类被隐藏的成员或调用父类构造函数
  • new 关键字用于显式隐藏父类同名成员(一般不用)

3.7 多态

父类方法标 virtual(虚方法),子类用 override 重写。同一个方法名,不同子类跑出不同结果。这就是多态的核心。

classWeapen{publicdoublePower{get;set;}publicdoubleSpeed{get;set;}publicvirtualvoidAttack(){Console.WriteLine($"攻击力:{Power},速度:{Speed}");}}classTank:Weapen{publicstringDir{get;set;}publicoverridevoidAttack(){Console.WriteLine($"坦克向{Dir}运动,速度{Speed},攻击力{Power}");}}classBullen:Weapen{publicstringType{get;set;}publicoverridevoidAttack(){Console.WriteLine($"子弹{Type},速度{Speed},攻击力{Power}");}}

好处:以后加新武器不用改已有代码,直接继承重写就行,符合"开闭原则"——对扩展开放,对修改关闭。

3.8 抽象类

用 abstract 修饰的类。当一个类中有方法无法确定具体实现时(比如"动物吃"——狗吃肉、猫吃鱼),把这个方法声明为 abstract,让子类去具体实现。

特点:

  • 抽象类不能实例化(不能 new)
  • 抽象方法必须在抽象类中
  • 抽象方法没有方法体,子类必须重写
  • 抽象类中也可以有非抽象方法

四、VS 常用快捷键

快捷键功能
F5运行程序
F7查看代码
Ctrl+K, Ctrl+C注释选中代码
Ctrl+K, Ctrl+U取消注释
Ctrl+K, Ctrl+F格式化全部代码
Ctrl+K, Ctrl+D格式化全部代码(另一种)
Ctrl+M, Ctrl+O折叠所有方法
Ctrl+M, Ctrl+L展开所有方法
Ctrl+Shift+F在文件中查找
Ctrl+H替换
Ctrl+R, Ctrl+E封装字段

五、自己容易错的问题

翻了一下这两周写的代码,整理了几个毛病:

  1. 命名乱。有的用拼音(myagelove_thing),有的拼错了(C_cricle),有的变量名太简略(rixj),过几天自己都看不懂。以后尽量用英文全称,遵循驼峰命名。
  2. 输入校验写了一遍又一遍。TryParse 加 while 循环的校验逻辑在 8 天作业里重复了不下 20 次,应该抽成一个通用方法复用。
  3. if 嵌套太深。个税计算那道题套了五六层 if,现在回头看眼睛都花了。用提前 return 可以减少嵌套层级。
  4. 变量名和内容对不上。有次把偶数和的变量取名ji(奇),奇数和的取名ou(偶),恰好反了。这种错编译器不报,但逻辑就是错的。
  5. 多余 using。每份代码顶上都有很多没用的引用,像是 System.Web、System.Xml.Linq,是 VS 自动补的,该删就删。
  6. 注释太少。前几天的代码基本没写注释,像推箱子 200 多行、个税计算,没有注释隔一周再看就得重新理逻辑了。

六、总结

学了两周下来,从刚开始的输入输出都不会,到现在能写继承多态的武器系统,进步还是能感受到的。几点体会:

  • 基础语法)敲多了自然就熟了,现在回头看前面的题感觉很简单
  • 堆栈和引用类型的概念虽然抽象,但理解了能解释很多奇怪现象
  • 面向对象开始有点绕,跟着作业多写几遍就好些了
  • 命名要规范、重复代码要抽方法、嵌套要减少——这几个习惯从一开始就养成最好

七、思维导图