资讯动态

C#100例刷题避坑指南:按三条主线搭建语法体系

发布时间:2026/10/18 0:25:27 来源:尧图企业网站定制
简介面向C#初学者的实例教程合集内含100个独立示例从变量、流程控制等基础语法出发系统覆盖面向对象、集合与数据结构、异常处理、LINQ、文件I/O、异步编程、多线程、网络通信、Windows窗体与WPF界面开发等核心主题并涉及经典Web应用项目结构有助于学习者将理论与实践快速结合。压缩包共1717个文件以C#源代码.cs、工程配置.csproj/.sln、可执行程序.exe为主同时包含图标、位图、数据库及配置文件等多种辅助资源整体约9.65MB解压后可分层检索使用。已有490人在CSDN学习下载适合自学、培训或作为教学案例库。每个示例均配有完整工程代码和可运行程序可独立编译验证通过动手实践读者能逐步掌握委托与事件、反射、单元测试、XML/JSON处理、跨平台开发等进阶技巧在真实编码场景中稳步提升C#开发水平。1. C#100例是什么不是题库是一张要自己排顺序的语法地图搜“c#100例”的多数不是缺题目而是缺一个能让自己坚持刷完的方案。第一次看到各类例题合集的开发者往往会照着顺序从第1例开始敲敲到第20例左右就放弃前面的例子太简单后面的例子突然跳到看不懂的集合与委托难度曲线像过山车。把人劝退的不是某个例子难而是例子之间没有递进关系。这套资料的内核是覆盖语法、面向对象、文件与数据处理的练习集合能帮你把零碎语法串成能独立写小工具的能力。适合刚学完基础语法但写不出完整程序的初学者也适合想快速补强C#实战手感、准备笔试的人。但直接从头刷是最容易翻车的打开方式。2. 先别急着敲代码把100例按三条主线拆开再决定顺序2.1 为什么100例会刷不完的两个结构性原因第一难度曲线不平滑。合集通常按“经典例题”组织不是按学习路径组织。前面的例子可能是“输出Hello World”和“计算两数之和”第30例突然变成“实现一个简易计算器”第60例又在处理文件读写。顺序看着合理但相邻例子之间的知识跨度不均匀读者刚把循环练熟马上要面对类与对象没有中间过渡。第二缺少场景归口。只按“第几例”记不按“解决什么问题”归类刷完就忘。学过“求最大公约数”“判断闰年”“冒泡排序”的人如果被问到“这三个例子共同用到了什么语法”往往答不上来。没有归口的例子记在脑子里的是散点有归口的例子才能沉淀成“遇到X类问题我有哪些工具”的检索能力。所以拿到任何一本C#练习集第一件事不是从第1例开始敲而是先花半小时把例子按语法能力线重新分组再按自己的水平挑顺序。这一步做完后面所有练习都会有一个明确的定位我当前在练什么、练到什么程度算过关。2.2 三条主线怎么划分语法基础、面向对象、文件与数据把常见例题拆开后会发现绝大多数例子落在三条主线上。我一般会把它们分成三组分组典型题目归属检验标准语法基础循环、分支、数组、字符串、递归如求水仙花数、九九乘法表、字符串反转不查资料能独立写完一个30行以内、含循环与字符串处理的控制台程序面向对象与集合类与对象、继承与多态、泛型、List/Dictionary/SortedList如学生成绩管理、图书信息登记能说出“为什么这道题用Dictionary而不是List”能自己设计一个包含两个类的模拟项目X文件、IO与LINQ文件读写、编码处理、路径拼接、LINQ查询、日志记录能把内存中的对象列表写入文件再读回来能对集合做分组、排序、筛选把题目往这三组里放的时候不用追求精确。拿不准的例子看它主要用的语法而不是看题目本身像什么。“计算平均分”既可以用数组做也可以用类加List做——放哪组取决于题目里有没有出现自定义类。分错不要紧三个组本身是学习阶段不是考试分类。这种分组方式有两个直接好处一是刷的时候知道自己处在哪个阶段不会因为跳到面向对象而慌二是将来复习时按组回看每组对应的检验标准能直接判断自己过没过关。检验标准比题目数量重要得多因为“刷过”不等于“会写”。2.3 筛选例子的可执行步骤与环境准备分组之后我习惯按“10 20 20”的节奏选例子先做10个语法基础题热身再做20个面向对象与集合题最后做20个文件与数据处理题。不需要把100例全部敲完精选50个覆盖三组的例子效果好于硬刷完整本。环境准备好之后第一步是在命令行确认SDK版本dotnet --version这一步的作用是确认当前机器的.NET环境可用版本号不同会影响后面控制台样例代码、文件编码等细节。如果命令报错先安装对应SDK安装完成后重新打开终端再执行。若你用的是带图形界面的开发环境也可以直接新建一个“控制台应用”项目看到默认模板代码生成即说明环境就绪。接下来用一组命令建好目录结构把要刷的例子按分组放进去mkdir CSharp100 cd CSharp100 dotnet new console -n SyntaxBase dotnet new console -n OopBase dotnet new console -n FileAndData这里给每组单独建一个控制台项目而不是在同一个项目里堆100个文件。原因很简单每个例子对应不同的命名空间和入口逻辑混在一起时Main方法会互相冲突。分组项目能让你随时在一个干净环境里单独跑某个例子排查问题时也容易定位。参数说明-n后面的名称是项目名同时也是目录名和默认命名空间命令会在当前文件夹下创建对应的.csproj工程文件。三个项目分别对应三条主线刷到哪类例子就进入哪个项目。不想用命令的话也可以用IDE的“新建项目”向导创建三个控制台工程效果一样。3. 用控制台案例跑通语法链路字符串与排序的完整写法3.1 从字符串反转开始把散装语法串成完整函数语法基础组里字符串反转是出现频率很高的例子。它的难点不在“倒着输出”而在于完整实现一个可供输入、处理、输出的小程序恰好覆盖变量声明、字符串处理、循环、方法封装和输入输出。using System; class Program { static string ReverseString(string input) { char[] chars input.ToCharArray(); Array.Reverse(chars); return new string(chars); } static void Main() { Console.Write(请输入一段文字); string input Console.ReadLine() ?? string.Empty; string result ReverseString(input); Console.WriteLine($反转结果{result}); } }逻辑说明ToCharArray把字符串转成字符数组Array.Reverse对数组原地反转new string(chars)再把字符数组合回字符串。Console.ReadLine()读入一行用户输入?? string.Empty是空值合并防止用户直接回车导致后续处理拿到null。这里把反转逻辑封装成方法而不是写在Main里是为了让例子更接近真实项目的写法。参数说明ReverseString接收string类型参数返回string类型结果在Main里调用时用字符串插值$...拼出结果。把这段代码放进前面建好的SyntaxBase项目里替代默认的模板代码按F5或执行dotnet run就能看到输入和输出。如果想提高难度可以改成“按单词反转”或“判断回文串”这两个变体分别会用到Split和循环比较属于同一语法链路内的自然延伸。3.2 排序与查找冒泡排序加二分查找为什么总被低估排序在100例里的出镜率极高。很多人觉得“现在有现成的Sort方法为什么还要写冒泡”但练习排序的目的一是理解比较与交换的底层过程二是为后面理解算法复杂度埋下种子。二分查找则和排序构成天然组合先排序再在有序序列里检索。using System; class Program { static void BubbleSort(int[] nums) { for (int i 0; i nums.Length - 1; i) { for (int j 0; j nums.Length - 1 - i; j) { if (nums[j] nums[j 1]) { int temp nums[j]; nums[j] nums[j 1]; nums[j 1] temp; } } } } static int BinarySearch(int[] nums, int target) { int left 0, right nums.Length - 1; while (left right) { int mid (left right) / 2; if (nums[mid] target) return mid; if (nums[mid] target) left mid 1; else right mid - 1; } return -1; } static void Main() { int[] nums { 42, 17, 8, 99, 3, 27 }; BubbleSort(nums); Console.WriteLine(string.Join(, , nums)); int index BinarySearch(nums, 27); Console.WriteLine($目标值索引{index}); } }逻辑说明冒泡排序通过相邻元素两两比较把较大的元素逐步“冒泡”到末尾。内层循环的nums.Length - 1 - i是关键每完成一轮外循环末尾就会多一个已经就位的大值不再需要参与下一轮比较。二分查找则不断把查找区间折半mid (left right) / 2取中间位置根据中间值和目标值的比较结果决定搜索左半区还是右半区找不到时返回-1。参数说明BubbleSort直接修改原数组所以不需要返回值BinarySearch的入参要求数组已经有序否则结果不可信。string.Join(, , nums)把整型数组转成以逗号分隔的字符串用于输出。如果把27改成不存在于数组中的数字BinarySearch会返回-1可以当作检查程序正确性的小实验。3.3 调试这些控制台例子的常用方式语法组的例子代码量都不大但如果结果不对不要盯着屏幕玄学猜错因。我一般按三件事排查先确认输入是否符合预期再看循环边界最后查变量类型。具体说冒泡排序最容易错的是内层循环写成j nums.Length - i多比较了一个已经排好的末尾元素不影响结果但会造成无用的比较二分查找最容易错的是left mid - 1和right mid 1写反导致死循环。用Console.WriteLine在循环里打印关键变量的值是最快的定位方法比如在冒泡内层循环里输出当前j和交换后的数组就能看到每轮排序的中间状态。例子都跑通后可以把打印语句删掉换成只输出最终结果。4. 文件与集合把100例里最常用的10个场景做成小工具4.1 为什么文件类例子是区分“会语法”和“能干活”的分水岭基础语法和面向对象练的是内存里的数据操作一旦程序退出所有结果都消失。文件与数据处理类例子增加了“持久化”能力把结果写到磁盘、从磁盘读入配置、把对象列表序列化到文件这些是真实小工具的基本形态。100例里属于这一组的通常包括统计词频、读取CSV、按条件过滤数据等。它们的共同结构是读入来源 → 处理 → 写出结果。这类例子也是很多人第一次明显感觉到“C#写文件居然要考虑这么多细节”的地方。编码、路径、资源释放每个点单独看都不难凑在一起就容易翻车。第5章的避坑清单里会展开其中几个这里先用一个完整的词频统计例子把主流程走通。4.2 读取文本并统计词频StreamReader与Dictionary的配合词频统计是文件与数据组的代表题目它同时用到文件读取、字符串分割、集合操作和排序。完成之后可以直接改造成日志关键词统计或配置项检查工具。using System; using System.Collections.Generic; using System.IO; using System.Linq; class Program { static void Main(string[] args) { string filePath args.Length 0 ? args[0] : input.txt; if (!File.Exists(filePath)) { Console.WriteLine(文件不存在 filePath); return; } Dictionarystring, int counts new Dictionarystring, int(); using (StreamReader reader new StreamReader(filePath)) { string line; while ((line reader.ReadLine()) ! null) { string[] words line.Split(new char[] { , \t, ,, . }, StringSplitOptions.RemoveEmptyEntries); foreach (string word in words) { string key word.ToLower(); if (counts.ContainsKey(key)) counts[key]; else counts[key] 1; } } } var topWords counts.OrderByDescending(pair pair.Value).Take(10); foreach (var pair in topWords) { Console.WriteLine(${pair.Key}: {pair.Value}); } } }逻辑说明先用File.Exists做前置检查避免文件不存在时抛异常StreamReader在using块里创建作用域结束时自动释放底层文件句柄这是C#处理资源的标准写法。每读一行就按空格、制表符、逗号和句号拆词用ToLower()统一小写保证“The”和“the”合并计数。Dictionary的ContainsKey判断和[]索引赋值完成累加最后用LINQ的OrderByDescending按次数排序Take(10)取前10个。参数说明args[0]支持在命令行传入文件路径比如dotnet run -- input.txt不传时默认读取当前工作目录下的input.txt。StringSplitOptions.RemoveEmptyEntries会过滤掉连续分隔符产生的空字符串这个参数不加的话统计结果里会出现空键。把这段代码放进FileAndData项目里在项目目录放一个文本文件再运行即可看到效果。4.3 用LINQ把循环改成查询表达式从“怎么算”到“要什么”词频统计里已经用了一次OrderByDescending。在文件类例子中LINQ的价值会更明显当需求从“统计词频”变成“找出所有长度大于5的单词并按出现次数排序”时用循环写要加不少嵌套用LINQ写只需要增加一行查询条件。using System; using System.Collections.Generic; using System.IO; using System.Linq; class Program { static void Main(string[] args) { string filePath data.csv; if (!File.Exists(filePath)) return; var lines File.ReadAllLines(filePath).Skip(1); var query from line in lines let fields line.Split(,) where fields.Length 3 let score int.Parse(fields[2]) where score 60 orderby score descending select new { Name fields[0], Score score }; foreach (var item in query) { Console.WriteLine(${item.Name}: {item.Score}); } } }逻辑说明这个例子模拟的是“读取成绩CSV跳过标题行筛选及格记录并按分数排序”。Skip(1)跳掉表头let引入中间变量避免在where和orderby里重复写int.Parse两个where连续使用时是“且”的关系代码按从上到下的顺序读比写一长串条件更清楚select new { ... }生成匿名类型只保留需要的字段。参数说明File.ReadAllLines一次性把整个文件读入字符串数组适合体积不大的数据文件大文件还是优先用StreamReader逐行读。fields.Length 3这个条件用于过滤掉格式不完整的行防止int.Parse(fields[2])抛异常。匿名类型new { Name ..., Score ... }是LINQ查询里非常常用的写法它的字段名在foreach里直接可用。如果CSV里包含引号包裹的逗号示例里的Split(,)会拆错真实场景需要换成专业解析器100例级别的练习不会涉及这一步。4.4 把例子升级成小工具的改造思路跑通例子后可以按“参数化输入、输出到文件、添加重复运行保护”三步把它改成真正能天天用的小工具。具体做法是把写死的文件路径换成命令行参数或配置文件把控制台输出换成File.WriteAllLines落到结果文件在用StreamReader读取时加入异常捕获文件被占用或权限不足时给出中文提示而不是一长串堆栈。这三个改造点分别对应真实工具的“可配置、可保存、可容错”。练习题只要求程序能跑小工具还要考虑用户会怎么用、程序会怎么挂。以词频统计为例加上输出到文件的功能之后它就不再只是一个练习而是一个能对日志文件做关键词排序的小工具。5. 刷C#100例的避坑清单五个最容易出现的翻车细节5.1 环境与运行层面的三个坑坑一代码和书里一模一样运行却说找不到入口。现象把例子代码完整敲进编辑器编译报错找不到合适的Main入口或提示入口冲突。原因新版模板默认使用顶级语句系统自动把最后一条语句当作入口旧版例子普遍带有显式的static void Main。两种入口写在同一文件里就会冲突只留Main时又可能和模板自动生成的顶级语句打架。解决打开项目文件二选一。想保留经典写法就把文件里的顶级语句删除保留类与Main想沿用新模板风格就把static void Main那一段删掉只留顶层的表达式语句。最简单的判断方式是看运行时报错指向哪一行删掉对应的重复入口。坑二控制台中文输出乱码或显示问号。现象程序里明明输入了中文运行时显示成???或者方格。原因不同平台的终端默认代码页不同而.cs文件保存的编码和终端代码页不一致时中文字符就显示异常。解决在Main入口处设置输出编码Console.OutputEncoding System.Text.Encoding.UTF8;。同时确认代码文件本身保存为UTF-8。这个设置只影响控制台输出不影响写入文件时的编码文件编码需要单独指定。坑三文件路径按相对路径写运行时总说找不到文件。现象代码写File.ReadAllText(data.txt)文件也确实放在项目目录里但程序运行时报错找不到该文件。原因命令行运行程序时当前工作目录不一定是程序集所在目录也不一定是项目目录。在IDE里运行和直接在终端dotnet run时的工作目录都可能不一样。解决练习阶段直接使用绝对路径最省事工具化阶段用Path.Combine拼接路径比如Path.Combine(AppContext.BaseDirectory, data.txt)。另外可以在项目文件里设置“复制到输出目录”让数据文件每次构建时自动拷贝到与程序相同的目录下这样相对路径就稳定了。5.2 语法与集合层面的两个坑坑四在foreach里修改集合编译能过运行就抛异常。现象写foreach (var item in list) { list.Remove(item); }运行到一半抛出“Collection was modified”异常。原因foreach默认基于迭代器遍历迭代期间修改集合会让集合的版本号变化迭代器检测到变化后立即终止并报错。这是C#集合的安全机制不是编译器抽风它防止你在遍历时出现漏元素或越界。解决需要边遍历边删除时用for循环从后往前遍历或者先收集要删除的元素遍历结束后再统一删除。后一种思路在代码里更常见var toRemove list.Where(x x.Score 60).ToList(); foreach (var x in toRemove) list.Remove(x);。注意ToList()必须调用否则延迟执行会导致在遍历尚未结束时仍修改原集合。坑五变量名与关键字混淆或者大小写不一致导致“看起来没问题但跑不了”。现象程序逻辑看起来完全正确编译却报标识符错误或者在别的语言里能用的命名习惯在C#里报错。原因C#区分大小写string是关键字而String是类型名Console不能写成console同时class、namespace等关键字不能用作变量名。不少从其他语言转过来的开发者会把类名首字母小写或把局部变量命名成var、object这类容易混淆的名字。解决命名遵循PascalCase与camelCase约定类名与方法名用PascalCase局部变量与参数用camelCase。如果错误指向某个标识符先检查大小写和是否与关键字同名。把int误写成Int这类错误在编译时会直接给出提示按提示修改即可不需要背完整的关键字列表。6. 把例子改造成自己的工具箱从抄写到变通的三个技巧6.1 给例子加一层输入变化刷完一个例子后不要急着做下一个。把输入变一下是性价比最高的复习方式字符串反转改成按单词反转冒泡排序改成按自定义对象某个属性排序词频统计改成统计日志级别出现的次数。输入变体让同一套语法在不同场景里被反复调用记忆会比单纯重做一遍牢固得多。6.2 用最简断言验证改造结果练习阶段的程序大多靠肉眼核对输出。改造例子时我习惯加几行最原始的断言代码static void TestReverseString() { if (ReverseString(abc) ! cba) throw new Exception(反转结果不正确); if (ReverseString() ! ) throw new Exception(空字符串处理不正确); Console.WriteLine(测试通过); }用throw new Exception当失败的信号比打印两行再人工比对更快。这个习惯不依赖任何测试框架适合单文件练习场景当项目变大、需要持续回归时再引入正式的单元测试项目也不迟。6.3 给每个项目建一个记录文件我会在每个分组项目里放一个简单的记录文件写上“这个项目里有哪些例子、每个例子的关键语法、踩过的坑”。看起来多花几分钟复习时却能把“做过但忘了”的时间省回来。很多练习集本身没有组织记录功能自己维护一份就让别人的100例变成了你自己的索引。关于工具化改造我有一条曾经的教训早期刷例子只追求“运行通过”从不关心输入路径和编码设置结果到了写真实小工具时同样的问题重新踩了一遍。后来养成的习惯是把任何例子的输入都改成可配置的哪怕只是一个命令行参数。这多花不了几分钟但会让每一个刷过的例子都具备变成工具的底子。100例不是用来背完的是用来在需要时快速取用的。希望帮到你也欢迎把这份分组方式用在你自己的练习清单里。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑