news 2026/10/10 6:10:15

用C# WinForms自制轻量定时提醒小工具:快捷时间选择与批量状态管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用C# WinForms自制轻量定时提醒小工具:快捷时间选择与批量状态管理

每天要处理的琐事太多太碎,系统闹钟、日历提醒和任务管理软件各有各的别扭。我直接用 C# 写了一款轻量定时工具,把快捷时间选择、计划备注和状态批量管理塞进一个不到几百 KB 的单文件里,平时就常驻系统托盘,到点弹窗,用了一年多非常顺手。这篇博文把整个工具从需求梳理、核心代码思路到实际踩坑的完整过程都拆开讲,适合想用自己写的顺手工位提升效率的开发者,也适合正在用 C# 做 WinForms 小工具的新手参考。

1. 系统闹钟、日历和重型任务软件都差点意思:逼我动手自研的核心原因

1.1 碎片化提醒的日常困境

我自己平时在职场里同时也是个"生活琐事重灾区":上午十点要提交周报,下午两点半要跟进客户邮件,傍晚六点要记得接孩子,晚上九点还有个在线课程要签到。这些提醒之间没有任何逻辑关联,但任何一个错过都挺麻烦。

以前的解决方案无非这么几种:

  • Windows 系统闹钟:到点响一声,响完就没了。没有上下文,响铃时经常想不起来"我当初因为这个提醒是打算干什么"。而且一次性设定,第二天全部重来。
  • 日历软件:Outlook 日历做日程没问题,但你为一个"35 分钟后跟同事对个 Qt 方案"这种随机事件单独建一条日历邀请,还是太隆重了。打开客户端、选时间、写事件、选提醒,四步下来,黄花菜都凉了。
  • 任务管理应用:Notion、Trello、滴答清单这些确实强,但对一个"提醒"场景来说都太重了。打开浏览器、登账号、加载云端数据,再到新建任务,启动成本远高于动作本身。我想做的事只是三秒内记一句话,到点它提醒我,不需要项目管理方法论。

这就陷入了一个很尴尬的中间地带:真正轻的没有备注和状态管理,能做状态管理的不够轻。反复折腾了几轮之后,我的结论是:与其在各工具之间将就,不如用 C# 自己写一个刚刚好的工具。

1.2 产品定位:轻才是第一需求

这个工具从第一版开始就给自己划定了明确边界,所有功能都围绕标题里那三个词:快捷时间选择、计划备注、状态批量管理。具体就是:

  • 单机桌面程序,不联网,不依赖云端。
  • 进程常驻系统托盘,平时完全隐形,到点才弹窗。
  • 主界面上 3 秒内能添加一条带备注的计划。
  • 所有计划集中在一个列表里,可以勾选批量修改状态。

这些功能如果放进大型任务管理软件里都有,但组合方式完全不一样。下面是几个方案的对比,我当初做选型的时候主要就是看几个关键维度:

维度系统自带闹钟日历/邮件客户端任务管理App自己写的轻量工具
添加一条提醒耗时15秒以上,流程繁琐30秒以上10-20秒,看网络3-5秒
是否支持备注不支持支持但格式重支持支持,轻量输入
状态管理无,响完即弃有,但绑定日程体系完备足够轻量的列表批量操作
资源占用极低高偏高极低,百MB级别内存内
常驻不打扰无感常驻但不适配提醒通知栏通知多托盘图标,到点才弹

说白了,市面上不缺功能强大的工具,缺的是把添加成本压到极限的那种小工具。这个产品定位听起来很简单,但实际设计功能时,我会反复问自己一个问题:这个功能会不会把"添加一条计划"的步骤从 3 秒变成 5 秒?如果会,就得重新设计交互。

1.3 技术选型:为什么选 C# 和 WinForms

技术栈的选择没什么纠结的。这套工具的典型使用环境就是 Windows 桌面,那我优先考虑的就是 C# + WinForms。

  • C#本身语法清晰,泛型、LINQ、异步都很顺手,做一个桌面小工具,从开发效率到后期维护都很舒服。
  • WinForms虽然经常被说老气,但对于单窗口、列表、按钮交互这类需求,它是天花板级的存在。控件齐、事件模型简单、资料多到搜不完。
  • 依赖少。我用 .NET 8 开发,发布时选择单文件模式,输出就一个 exe,连 .NET 运行时都可以一起打包进去,换台电脑拷过去直接双击就能跑。

有人会问说现在不是很流行 WPF 或者 MVVM 吗?我也想过,但很快否掉了。原因很简单:这个工具的核心是"轻",UI 复杂度远没有到需要 ViewModel、Command、BindableBase 那一套的程度,引入 MVVM 框架反而会让代码膨胀。直接用 Code-Behind 处理事件,文件小、逻辑直白、热启动速度快。这种尺度的工程,去掉所有不必要的抽象,就是最好的架构。

2. 快捷时间选择的交互设计:预设时间片和自定义时间的组合逻辑

2.1 相对时间优先:90% 的职场提醒是"XX 分钟后"

这个工具最有成就感的功能其实是快捷时间选择。一开始我还想当然地照常规闹钟去做,给用户一个DateTimePicker控件让他选"几点几分"。但真正用起来之后发现,我的使用习惯根本不是这样。

大多数时候我需要的提醒是:"35 分钟后要去开会"、"20 分钟后抢个秒杀"、"1 小时后把代码提交了"——是相对时间,不是绝对时间。绝对时间需要我打开日历看现在几点、还要心算一个差值,这是一个明显的认知负担。

所以我最后的方案是两套入口并行:

入口适用场景交互方式
预设时间片按钮短倒计时型提醒点击"30分钟"直接添加
DateTimePicker明确的绝对时间型提醒选择具体日期和时间后添加

具体来说,主界面顶部就是一行输入框 + 一排按钮。输入框中写好计划的标题(比如"给客户回邮件"),然后可以直接点右侧的"15分钟""30分钟""1小时""2小时""半天""一天"这几个预设按钮,点了就直接创建一条倒计时计划。如果你要的是固定时间,比如"明天上午 9 点",那就在旁边的DateTimePicker里选好具体时间再点添加。

这个交互设计我试过很多次,最后确认了核心原则:方案一:人不动,时间动。用户输入完标题,手都不用离开键盘上方,伸一根手指点一下时间按钮就够了。整个添加操作耗时不超过两秒,这在日常使用中极其重要——你正在忙的时候,两秒钟挤出来很容易;超过五秒的操作,很多时候就随手用白纸记了。

2.2 WinForms Timer 轮询:一个全局 Timer 比每条计划一个 Timer 靠谱

再来看技术实现。这个功能里最容易出问题的其实是定时机制。做定时提醒,脑子里第一反应可能是:每条计划创建一个 Timer 实例。这个方案只适合计划极少的情况,一旦计划多了,你会遇到两个问题:

  1. 每个 Timer 都是独立对象,生命周期你得小心翼翼地管理,删除计划时忘了 Dispose,内存和句柄都会缓慢泄漏。
  2. 多条 Timer 醒来的时间点不一致,批量改状态、暂停、通知弹窗的逻辑会变得无比混乱。

我的做法是:全局只维护一个System.Windows.Forms.Timer,每秒钟 Tick 一次,每次扫描整个计划列表,把到点的计划筛选出来统一处理。

var timer = new System.Windows.Forms.Timer(); timer.Interval = 1000; timer.Tick += (s, e) => { var now = DateTime.Now; var duePlans = _plans .Where(p => p.Status == PlanStatus.Pending && p.DueTime <= now) .ToList(); foreach (var plan in duePlans) { plan.Status = PlanStatus.Running; // 先标记为已触发 ShowReminderForm(plan); // 在 UI 线程中弹出提醒 } RefreshListControl(); // 刷新列表视图 }; timer.Start();

注意这里我用的是System.Windows.Forms.Timer,而不是System.Threading.Timer。这两个名字特别像,实际行为差别很大:

  • System.Windows.Forms.Timer的 Tick 事件回调运行在 UI 线程上。这意味着事件里你可以直接操作 TextBox、ListView 等控件,不需要Invoke。
  • System.Threading.Timer是线程池里的定时器,回调线程完全不是 UI 线程,直接在回调里更新控件会抛InvalidOperationException跨线程操作异常。这个坑在 C# 论坛和热搜里极其常见,几乎每个写 WinForms 的人都被它坑过。

有人可能会担心每秒扫描一次会不会浪费。我实际测过,一个普通列表遍历几千条记录的开销是微秒到几十微秒级别,不到一毫秒的 CPU 时间,比起数据库 IO、网络请求根本不值一提。全局轮询是这把场景里的最优解,不采购额外内存,也不用处理复杂的定时器生命周期。

2.3 计划备注:为什么越短越有用

标题里提到的"计划备注"也是经过反复思考才定下来的。一开始我甚至觉得备注是多余的,提醒弹窗显示标题不就够了?结果用了几次之后发现:不够。

比如我设置了一条标题为"项目管理会"的提醒,到点弹窗时我盯着它愣了几秒,脑子里全是问号:这个会在哪个会议室?我需不需要提前打印材料?是线上还是线下?这些上下文信息完全没被带走,提醒就只是个铃声,没有任何行动指导价值。

于是第二版加入了备注字段,添加计划时输入框标题下方可以填一行备注(支持多行,但我个人建议限制在 50 字以内)。备注的作用不是写长篇大论,而是记录回答"到点后我要干什么"这个问题的关键信息:

  • 会议室是"3F-02",备注写"3F-02,提前 5 分钟到"
  • 客户邮件要回的要点,备注写"回复报价,附 8 月合同扫描件"
  • 接孩子的路上要买的东西,备注写"放学门口接,顺路买牛奶和吐司"

因为方案里的所有信息都在一个列表里,备注必须能在一扫之间读完,超过两行的备注我会改成描述更精简的句子。这个约束反而逼着我在输入时整理思路,把真正重要的话留下来。

3. 状态批量管理:计划从待处理到完成的一条清晰流转路径

3.1 状态机设计:四种状态足够覆盖全局,不要多余的复杂度

计划加进来之后不能被一个个丢在列表里,状态管理必须跟上。我给每条计划设计了四种状态,刻意没有引入第五种:

  • Pending:待提醒,等待时间到达。
  • Running:已触发,人可能正在处理这件事,但还没标记完成。
  • Completed:已完成。
  • Cancelled:已取消,根本不打算执行。

这四种状态本质上对应了计划生命周期的四个节点:未到时间 — 已到时间但还没做完 — 做完 — 放弃。有人会建议加"Overdue 逾期""Postponed 推迟""Doing 进行中"之类,我测试过加了之后反而让列表变得难以扫读:状态种类越多,用户做判断时需要阅读的信息越多。

实际实现上,一个含 Id 的后端实体类加一个前端显示映射就够了:

public enum PlanStatus { Pending = 0, Running = 1, Completed = 2, Cancelled = 3 } public class PlanItem { public int Id { get; set; } public string Title { get; set; } public string Note { get; set; } public DateTime DueTime { get; set; } public PlanStatus Status { get; set; } }

前端展示用一个ListView,在大图标模式下每条计划显示成一排,根据 Status 映射前景色和背景色。Pending 是黑色,Running 是深蓝色,Completed 是灰色(并显示完成时间),Cancelled 是浅灰色再加删除线。整个映射表写在一个静态方法里,刷新列表时直接查表,不需要到处散落颜色常量。

3.2 批量操作是省时间的灵魂:多选、右键菜单与快捷键

状态管理的价值在"批量"这两个字上体现得淋漓尽致。如果一次只改一条计划状态,那用普通 Todo 应用也没差。但真实职场场景里,状态变更往往是批量发生的:

  • 早上进办公室,先看列表里所有"待提醒"的计划,把昨天遗留的几条 Running 计划全部标记 Completed。
  • 下午例会前,把今天务必要完成的三条计划选中,统一标记为 Running(表示"我现在开始集中攻这几件")。
  • 临下班,把拖了一天已经没意义了的几条计划一起取消。

操作设计是:ListView支持多选。按住 Ctrl 或 Shift 点击可以选多条,Ctrl+A 全选。选中之后,右键菜单里提供以下操作:

菜单项行为是否弹确认
标记为已完成批量修改状态,记录完成时间否
标记为进行中批量修改状态否
标记为已取消批量修改状态否
复制为新计划把选中项拷贝成新的 Pending 计划否
删除计划从文件中永久移除是,弹确认框

快键和右键菜单配合使用非常顺手:F2 编辑、Delete 删除、空格切换选中,回车触发"标记为已完成"。实测下来,每天晚上复盘时把当天二十几条计划清一遍,全程不超过十秒。

这里有一个特别值得说的设计决策:批量修改状态不要弹确认框,但批量删除必须弹确认框。状态改错了随时可以改回来,柯南式误操作成本很低;删除不可恢复,数据丢了就是丢了。所以我把确认逻辑和可逆性绑在一起,越容易逆的操作越不需要确认。

3.3 轻量持久化:JSON 文件方案,不碰数据库

计划数据需要保存,程序退出后再启动时恢复。这个需求我用一个 JSON 文件解决,不引入 SQLite 或任何数据库。

文件放在可执行目录下的plans.json,结构就是一个List<PlanItem>的序列化结果。用System.Text.Json读写,代码量非常少:

public void SavePlans(string path) { var json = JsonSerializer.Serialize(_plans, new JsonSerializerOptions { WriteIndented = true }); // 先写临时文件,再替换正式文件,避免断电导致 JSON 损坏 var tempPath = path + ".tmp"; File.WriteAllText(tempPath, json, Encoding.UTF8); File.Delete(path); // 注释准备调整 File.Move(tempPath, path); } public void LoadPlans(string path) { if (!File.Exists(path)) return; var json = File.ReadAllText(path, Encoding.UTF8); _plans = JsonSerializer.Deserialize<List<PlanItem>>(json) ?? new List<PlanItem>(); }

写文件的时候特意做了先写临时文件再覆盖的处理。别小看这一步,我有一次程序运行时突然断电,重启后发现plans.json里全是乱码,几十条计划全丢了。后来的临时文件方案虽然不能完全防住断电,但损坏概率大幅降低,至少在正常退出和大多数异常退出场景下是安全的。

不需要数据库的理由也很实际:这个工具的数据量是条级别,几百条计划撑死也就几十 KB,一个 JSON 文件可读、可改、可备份,遇到数据问题打开文件直接就能诊断。SQLite 在这个尺度下只会引入依赖和管理成本。

3.4 列表排序:未处理的永远在最上面,干净的完成区沉底

状态管理离不开列表排序,排序逻辑我用了一个简单但极其有效的规则:

  1. 未处理(Pending + Running)计划按DueTime升序排在最上面,最近要到点的排第一,醒目。
  2. 已完成(Completed)计划沉底,按完成时间倒序,最近刚完成的排在完成区最上面,方便回溯。
  3. 已取消(Cancelled)计划默认折叠在一个分组里,不在主视图中占位。

这个排序带来的体验变化是革命性的。之前的版本里所有计划混在一起,每天早上一打开,列表乌泱泱一片,让人下意识想逃避。现在打开第一眼看到的就是"现在要我处理什么",完成区安静地躺在下面,成就感来自看着它的高度一天天增长。

4. 踩过的真实坑:Timer 线程、最小化托盘和删数据的误操作

4.1 Timer 访问控件:从偶发闪退到理解 UI 线程

这个坑值得一提,因为几乎每个 C# WinForms 开发者都会踩到,我当年在另一个项目里也摔过。

早期版本里我曾经用过System.Threading.Timer做每秒扫描。这玩意儿的回调默认跑在线程池线程上,所以当我在回调里直接写listView.Items.Clear()或者statusLabel.Text = "..."时,程序运行到某个瞬间就突然闪退了。控制台里打印的异常信息永远都是:"线程间操作无效:从不是创建控件"listView"的线程访问它"。

这个问题在热搜词里出现频率极高,"c# timer 访问控件""c# winform 如何更新状态栏与进度条"搜出来的结果绕不开 Invoke。当时的正确解决方法是包一层BeginInvoke:

private void UiSafeAction(Action action) { if (listView.InvokeRequired) listView.BeginInvoke(action); else action(); }

这样写本身是没问题的,但我在这个轻量工具里更推荐前文说到的方法:直接改用System.Windows.Forms.Timer,让所有逻辑都天然跑在 UI 线程上,源码里少了一个分支,脑子里的线程模型也简单一截。轻量工具不该把复杂度揽到自己身上,能用简单 API 解决,就不引入多线程。

4.2 最小化到托盘后,提醒窗口怎么弹才不"隐身"

程序要常驻,必然要做最小化到托盘:关闭主窗口不要退出程序,而是缩小为托盘图标。这一步实现了之后,又冒出来一个新问题:窗口最小化到托盘后,到点弹出提醒窗口,用户那边往往根本看不见。

为什么看不见?因为当主窗体是隐藏状态时,弹出的提醒窗体如果不特意设置TopMost,它只会作为普通窗口出现在任务栏上。如果用户当时正全屏看文档、开会投屏、或者人根本不在电脑前(比如去接水了),那就和没提醒一样。

我的解决方式是组合拳:

  1. NotifyIcon托盘图标常驻,气泡显示提醒摘要(标题 + 备注前两行)。
  2. 真正的提醒窗体设置为TopMost = true和ShowInTaskbar = true,保证它压在所有窗口最上面弹出来。
  3. 提醒窗体默认带一个高亮的红色标题栏,视觉上强提醒,关闭按钮旁边加一个"稍后提醒(5 分钟)"按钮,可以把同一计划延迟五分钟再弹。

试了几周之后,我甚至发现一个反直觉的事情:稍微让提醒窗体丑一点、大一点、明显一点,反而更受欢迎。因为它的职责就是打断你,不需要优雅,需要你没法忽略。

4.3 数据删除的误操作保护:Ctrl+Z 撤销删除

有一次我在列表上批量把"已完成"状态的计划全选删掉,手一抖把第二天的几条 Pending 计划也一起选中删了。当时那个版本删除前没有确认框,数据直接从 JSON 文件里抹掉了,我再找回时已经晚了。

那之后我做了三层防护,现在基本不会再误删重要计划:

层级防护策略说明
第一层删除前弹确认框,显示数量按"确定"才会真正执行
第二层删除项进入内存回收站保留最近删除的 20 条,供 Ctrl+Z 撤销
第三层列表底部增加"查看回收站"按钮手动恢复错删的计划,删除时记录操作日志

实现上,删除执行前把所有PlanItem快照放到一个Stack<List<PlanItem>>里,Ctrl+Z 时从栈顶弹出一个快照直接恢复整个列表。这个方案简单粗暴,但对单机小工具非常可靠。撤销删除的体验和写 Word 一样,按一下键盘就安心了。

还有一个容易被忽略的小坑:删除前注意检查计划里是否有DueTime已经过去但状态还是 Pending 的"僵尸计划"。这种计划建议在删除确认框里用红色提示"包含 X 条已过期未处理计划",避免用户糊里糊涂地删掉还没处理的重要事项。

5. 从"能用"到"好用":提醒弹窗细节、自启动和其他扩展方向

5.1 提醒窗口的细节:字号、按钮、声音缺一不可

提醒窗口的设计,其实一开始只是想着"能弹出来就行"。但真正用起来,细节决定成败。

  • 字号大:提醒窗口标题至少 18 号以上,为了目标是在 3 米外扫一眼也能看清是什么事。
  • 时间明确:窗口内显示"现在"和"原定提醒时间"两个时间。特别是你不在电脑前回来时,看到"原定 14:30 提醒,现在 15:10",立刻能判断已经晚了多久。
  • 备注完整显示:提醒窗口不用文本框,用Label自动换行。避免用户还得点开详情才能看到备注。
  • 声音友好:我不用系统默认的"叮",而是通过SoundPlayer播放SystemSounds.Exclamation,同时在不打扰的前提下不循环播放。

另一个很实用的补充是"稍后提醒"的间隔选择。提醒窗里提供"5 分钟""10 分钟""30 分钟"三个按钮,点击后计划状态会从 Running 回退为 Pending,再把DueTime延后对应分钟数。这比重新创建一条计划要自然得多。

5.2 自启动 + 启动即最小化 + 简单日志

既然定位是常驻工具,那开机自启是刚需。实现方式就是在注册表的HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run下加一个指向 exe 的键值。这样只影响当前用户,不需要管理员权限,卸载时删掉键值即可。

自启动之后,程序需要支持启动参数-minimized,否则每次开机都会弹出一个完整主窗口,很烦人。我在Main函数里做参数判断,带了这个参数就只初始化托盘、不显示主窗体。

日志功能我一开始觉得没必要,但后来坚持加了一行。每次状态变更时向log.txt追加一行记录,比如:

2025-01-07 15:00:12 | 计划#23 到点提醒:客户邮件跟进 2025-01-07 15:01:44 | 计划#23 标记完成

在月复盘时,用 Excel 导入这个 log 文件,直观看到自己每天完成了多少条计划、平均延迟多久、哪类计划总是被取消。这个日志不是给程序看的,是给自己看的。工具提供了数据,人才能真正意识到自己把时间花在了哪里。

5.3 我这一个多月的实际使用数据与体感

这个工具从开发完成到现在,我每天都用它,一个多月下来统计了一些数字:

  • 平均每天添加计划 9-13 条,绝大多数都是"30 分钟"和"1 小时"这两个快捷按钮添加的。
  • 添加一条计划的平均用时大约 3 秒(标题 + 点按钮),比之前用 Outlook 日历至少快了 5 倍。
  • 当天完成率从以前的 40% 左右提升到 85% 以上。原因不是我的自制力变强了,而是因为所有低成本的提醒都被集中摆在了眼前,少了"忘了这回事"的情况。
  • 这条工具最值钱的其实是"我可以完全忘掉它":添加计划时不用惦记着设闹钟、不用安排分类、不用考虑优先级,删掉那些过程步骤,计划本身的执行反而更顺畅。

有人说提醒工具会让人过度依赖,我反倒觉得这是好事。人的大脑不该用来记这些碎片时间点,把记忆外包给工具,节省出来的注意力去处理真正需要思考的工作,这才是用钱的常识。

5.4 后续扩展的想法:从托盘工具到个人时间数据源

最后也想聊聊后续可扩展的方向,倒不是说要加多少功能,而是给有类似想法的人提供一个思路参考:

  • 计划备注里直接支持环境变量和外部程序调用。比如备注写成%COMSPEC% /c start daily-report.md,到点弹出提醒时可以直接打开对应文档,甚至执行一个外部命令。
  • 导出 CSV 做周复盘。目前 log 里的数据是纯文本,扩展一步就是做成结构化 CSV,更快地和表格软件打通。
  • Webhook 通知。如果希望手机也收到提醒,可以后续在程序里加一个 HTTP 请求到个人服务器的接口,到点后转发一条通知。这属于可选功能,不做也不影响本机体验。
  • 多套提醒方案。比如节假日跳过、滚动提醒,这些在现在基础上做起来都不复杂,但我不打算全塞进来——轻量工具的底线是永远别往里面塞超过需求的功能。

做这个小工具收获最大的不是我写了多少行代码,而是我逐渐理解了"工具给人带来幸福感"到底是什么意思:把最常用的操作做到 3 秒级别,把状态管理压缩到一个列表一次右键,然后把所有需要记忆的部分交给文件,整个人反而获得了更多可支配的注意力。这些设计决策其实都围绕同一个核心——降低启动成本。文章里所有坑和优化也都来自这个原则,如果你也想做个类似的个人小工具,建议别急着加功能,先把自己"最常用的那个动作"做到极致的简单,剩下的自然会慢慢长出来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 6:09:23

第五篇:Keepalived + LVS 四层负载均衡高可用实战:DR 模式全流程

开篇Keepalived 不只是"VIP 漂移工具"——它天生就是为 LVS&#xff08;Linux Virtual Server&#xff09;设计的。很多人不知道&#xff0c;Keepalived 的看家本领就是管理 LVS 集群&#xff0c;实现四层负载均衡 高可用的一体化方案。本文作为 Keepalived 系列第 …

作者头像 李华
网站建设 2026/10/10 6:07:00

web.py 快速入门:8 行代码构建你的第一个 Python Web 应用

后端Web框架 【免费下载链接】webpy web.py is a web framework for python that is as simple as it is powerful. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/we/webpy 点击查看 免费下载 web.py 是一个"简单而强大"的 Python Web 框架&#xff0c;其…

作者头像 李华
网站建设 2026/10/10 6:06:45

多重继承与菱形继承:虚继承到底解决了什么

多重继承&#xff08;multiple inheritance&#xff09;是 C 少数几个「别的语言基本不给」的特性。它本身不难用&#xff0c;真正的坑在菱形继承&#xff08;diamond inheritance&#xff09;&#xff1a;当 D 同时继承 B1 和 B2&#xff0c;而这两者又都继承自 A 时&#xff…

作者头像 李华
网站建设 2026/10/10 6:06:38

Linux --传输层协议 UDP

传输层是干什么的&#xff1f;传输层位于网络层之上、应用层之下&#xff0c;核心任务只有一个&#xff1a;负责把数据从发送端传输到接收端。网络层&#xff08;IP&#xff09;负责把数据送到目标主机&#xff0c;但主机上可能同时运行着很多程序&#xff08;浏览器、QQ、微信…

作者头像 李华
网站建设 2026/10/10 6:06:35

pprof 火焰图(Flame Graph)阅读与热点代码重构实战

pprof 火焰图&#xff08;Flame Graph&#xff09;阅读与热点代码重构实战 一、核心概念与架构设计 上一篇用 go tool pprof -top 看到了函数级的耗时排名&#xff0c;但排名有一个致命缺陷&#xff1a;它丢掉了调用关系。fmt.Sprintf 占 8% 的 CPU&#xff0c;这 8% 是谁调用它…

作者头像 李华
网站建设 2026/10/10 6:06:07

工业相机标定实战:内参模型选择与双目标定闭环

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华