【PlainCEETimer】两年了,分享一下开发感受

本文最后更新于:3 天前

前言

时间过得很快啊,距离 PlainCEETimer (原 CEETimerCSharpWinForms) 首发已经过去两年了。这篇文章主要分享一些感受,为什么两年了我还执着于 “高考倒计时” 这个几乎没有存在感的项目。

PlainCEETimer 作为我在 C# 领域的首作,说实话当时还没有什么编程概念。尽管我在那之前学过一点点 C#,但突然将学习过的知识投入使用也会让我有些措手不及,毕竟以前都是看,现在轮到自己亲手来写了。但不懂就学呗,我的学习来源很多:参考书、微软文档、其他开源项目。因此我学习 C# 的方式几乎是零基础上手,边写项目边学习。直到现在两年过去了,我已经对 C# 有一定的掌握。

2023/10/28 v1.0 发布

是的你没有看错,1.0 就长这个样子,图片为真实大小,无缩放。它不能拖动,不能更改颜色/字体,不能设置考试名称/日期时间,只是一个单独的窗口。别看这个东西长得挺简单的,这在当时对于我这个编程小白来说可是一个大工程,由于各方面都一窍不通,所以也耗费了大量的时间,结果才做出这么个玩意儿,不过当时想的也是能看就行。后来慢慢的,身边的同学,甚至我自己,都对这个倒计时有了更高的要求,所以就一直做到了现在。

另外可能有朋友疑惑为什么仓库里面没有 1.0 版本 (准确来说是没有 1.6 之前的版本),虽然原因在 1.6 的更新日志里有写,但表述的含糊不清:

为什么没有 v1.6 之前的 Release?因为一些特殊原因所以删库重开了,所有从 1.0 开始的更新日志已合并。

这里告诉大家真实原因:其实也不是什么大问题,就是因为当时软件的图标是在网上随便找的。后来意识到可能有版权问题,可是又不能直接卸下图标,因为 GitHub 是有提交记录的,就算我在后续版本中改用其他图标,旧图标仍然在仓库可见。于是索性就直接删库重开了。

但是为了给自己留下纪念,我当然没有直接删除仓库,而是改名为 CEETimerCSharpWinFormsNull 并设置为私有,不对外公开而已。也就是说 WangHaonie/CEETimerCSharpWinForms 并没有消失,它在我的仓库列表中仍然可见:

最后再来看看 1.0 的代码行数:(结果来自专业的源代码行数计算工具 cloc)

1
2
3
4
5
6
7
8
9
10
11
12
-------------------------------------------------------------------------------------
File blank comment code
-------------------------------------------------------------------------------------
.\Form1.Designer.cs 7 17 55
.\Form1.cs 11 0 43
.\Properties\Resources.Designer.cs 9 26 38
.\Properties\AssemblyInfo.cs 4 17 17
.\Properties\Settings.Designer.cs 5 9 16
.\Program.cs 2 1 15
-------------------------------------------------------------------------------------
SUM: 38 70 184
-------------------------------------------------------------------------------------

如你所见,毫不夸张,184 行,就能完成一个高考倒计时。

2025/5/11 v5.0.1 发布

两年后的今天,v5.0.1 正式发布,这一路上高考倒计时的功能越来越丰富,内部代码也越来越规范和完善。先来看看源代码行数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
------------------------------------------------------------------------------------------------------------------
File blank comment code
------------------------------------------------------------------------------------------------------------------
.\PlainCEETimer\Forms\SettingsForm.Designer.cs 5 227 773
.\PlainCEETimer\Forms\MainForm.cs 96 10 672
.\PlainCEETimer\Forms\SettingsForm.cs 90 5 655
.\PlainCEETimer\Controls\ListViewDialog.cs 49 19 275
.\PlainCEETimer\Controls\AppForm.cs 65 103 270
.\PlainCEETimer\Dialogs\RuleDialog.Designer.cs 6 86 262
.\PlainCEETimer\Modules\App.cs 24 0 214
.\PlainCEETimer\Interop\CommonDialogHelper.cs 35 7 186
.\PlainCEETimer\Dialogs\RuleDialog.cs 35 0 184
.\PlainCEETimer\Forms\AboutForm.Designer.cs 6 38 131
.\PlainCEETimer\Forms\DownloaderForm.cs 18 0 130
.\PlainCEETimer\Dialogs\CustomTextDialog.Designer.cs 6 53 124
.\PlainCEETimer\Dialogs\ExamInfoDialog.Designer.cs 6 50 122
.\PlainCEETimer\Modules\Enums.cs 17 12 120
.\PlainCEETimer\Modules\OptimizationHelper.cs 15 0 112
.\PlainCEETimer\Modules\Configuration\ConfigObject.cs 19 0 111
.\PlainCEETimer\Forms\DownloaderForm.Designer.cs 5 35 106
.\PlainCEETimer\Modules\Validator.cs 23 12 103
.\PlainCEETimer\Dialogs\ExamInfoDialog.cs 16 0 95
.\PlainCEETimer\Dialogs\AppMessageBox.cs 13 0 87
.\PlainCEETimer\Modules\Configuration\ExamInfoObject.cs 13 0 78
.\PlainCEETimer\Controls\ListViewEx.cs 14 0 76
.\PlainCEETimer\Dialogs\AppMessageBox.Designer.cs 6 35 75
.\PlainCEETimer\Modules\MessageBoxHelper.cs 26 16 72
.\PlainCEETimer\Dialogs\RulesManager.cs 11 0 70
.\PlainCEETimer\Modules\Http\Downloader.cs 7 0 69
.\PlainCEETimer\Controls\NavigationBar.cs 11 10 67
.\PlainCEETimer\Dialogs\CustomTextDialog.cs 11 0 66
.\PlainCEETimer\Controls\AppDialog.cs 9 0 64
.\PlainCEETimer\Modules\Configuration\DisplayObject.cs 12 0 63
.\PlainCEETimer\Interop\ThemeManager.cs 16 9 58
.\PlainCEETimer\Forms\AboutForm.cs 7 0 54
.\PlainCEETimer\Controls\ColorDialogEx.cs 8 0 51
.\PlainCEETimer\Forms\MainForm.Designer.cs 8 17 51
.\PlainCEETimer\Modules\UACHelper.cs 15 7 51
.\PlainCEETimer\Modules\Configuration\CustomRuleObject.cs 13 0 49
.\PlainCEETimer\Modules\Updater.cs 5 0 49
.\PlainCEETimer.Natives\ThemeManager\ThemeManager.cpp 17 10 46
.\PlainCEETimer\Modules\JsonConverters\CustomRulesConverter.cs 7 0 46
.\PlainCEETimer.Natives\ListViewHelper\ListViewHelper.cpp 19 16 43
.\PlainCEETimer.Natives\TaskbarProgress\TaskbarProgress.cpp 10 7 40
.\PlainCEETimer\Modules\Configuration\DefaultValues.cs 6 0 39
.\PlainCEETimer\Modules\PlainButtonBase.cs 5 0 39
.\PlainCEETimer\Controls\ComboBoxEx.cs 12 7 38
.\PlainCEETimer\Controls\FontDialogEx.cs 5 0 37
.\PlainCEETimer\Controls\PlainGroupBox.cs 4 6 35
.\PlainCEETimer\Modules\Configuration\ConfigHandler.cs 4 0 34
.\PlainCEETimer\Modules\RegistryHelper.cs 10 0 31
.\PlainCEETimer\Controls\PlainNumericUpDown.cs 3 0 29
.\PlainCEETimer\Modules\ProcessHelper.cs 3 8 29
.\PlainCEETimer\Controls\PlainTextBox.cs 4 0 27
.\PlainCEETimer\Modules\JsonConverters\ColorSetConverter.cs 5 0 27
.\PlainCEETimer\Modules\JsonConverters\FontFormatConverter.cs 5 0 26
.\PlainCEETimer\Interop\ListViewHelper.cs 4 0 25
.\PlainCEETimer\Modules\Constants.cs 0 0 25
.\PlainCEETimer\Modules\Extensions.cs 10 5 24
.\PlainCEETimer\Interop\IconHelper.cs 6 5 23
.\PlainCEETimer\Modules\ContextMenuBuilder.cs 6 0 23
.\PlainCEETimer\Modules\Http\HttpService.cs 4 0 23
.\PlainCEETimer\Controls\PlainButton.cs 3 0 22
.\PlainCEETimer\Modules\JsonConverters\PointFormatConverter.cs 4 0 22
.\PlainCEETimer\Dialogs\ExamInfoManager.cs 3 0 19
.\PlainCEETimer.Natives\MemoryCleaner\MemoryCleaner.cpp 8 5 18
.\PlainCEETimer\Modules\JsonConverters\CustomColorsConverter.cs 2 0 18
.\PlainCEETimer\Interop\TaskbarProgress.cs 4 0 17
.\PlainCEETimer\Modules\Configuration\GeneralObject.cs 7 0 17
.\PlainCEETimer\Modules\ResponseObject.cs 4 0 16
.\PlainCEETimer\Controls\Hyperlink.cs 2 0 14
.\PlainCEETimer\Controls\NavigationPage.cs 1 3 14
.\PlainCEETimer\Interop\RoundCorner.cs 2 0 13
.\PlainCEETimer\Modules\WindowsBuilds.cs 0 0 13
.\PlainCEETimer\Program.cs 1 0 13
.\PlainCEETimer\Controls\PlainLinkLabel.cs 1 0 12
.\PlainCEETimer\Modules\Configuration\ColorSetObject.cs 2 0 12
.\PlainCEETimer\Properties\AssemblyInfo.cs 1 0 12
.\PlainCEETimer.Natives\RoundCorner\RoundCorner.cpp 7 7 11
.\PlainCEETimer\Modules\JsonConverters\ExamTimeConverter.cs 1 0 11
.\PlainCEETimer\Interop\MemoryCleaner.cs 1 0 10
.\PlainCEETimer\Modules\Http\DownloadReport.cs 0 0 10
.\PlainCEETimer\Modules\ISubDialog.cs 1 0 10
.\PlainCEETimer\Controls\PlainCheckBox.cs 1 0 9
.\PlainCEETimer\Controls\PlainRadioButton.cs 1 0 9
.\PlainCEETimer\Modules\ComboData.cs 0 0 8
.\PlainCEETimer\Modules\ICommonDialog.cs 1 0 8
.\PlainCEETimer\Modules\IListViewObject.cs 1 0 5
.\PlainCEETimer.Natives\pch.cpp 0 0 1
------------------------------------------------------------------------------------------------------------------
SUM: 949 830 6848
------------------------------------------------------------------------------------------------------------------

6848 行,这个数字在众多同类开源项目中其实并不算太多,但对于 1.0 仅用 184 行的代码量就能完成,确实挺夸张的。增加了整整 6664 行代码,这当中发生了什么变化?因为编写软件不光要满足用户的需求,还要与操作系统的设计达成一致,保证用户所需功能正常运行的同时也能更适应不同的系统环境。这个我不太说得清,如果屏幕前的你是个软件开发者的话,你应该能明白我的意思。概括一下就是除了要做用户需要的功能以外还要写很多不属于用户所需功能的代码,这些代码虽然写与不写,用户都无法察觉,但并不算累赘,而是一种约定俗成,是构建软件、增强用户体验的基石,让用户在任何环境下都能获得舒适、可靠的使用体验。

要我说,估计 5.0.1 真正最终实现倒计时的代码不会超过 300 行,感兴趣的朋友可以去数一下,也就只有那个 CountdownCallback(object) 方法及其调用的相关方法。

2025/7/28 v5.0.5.1 发布

v5.0.5.1 与 v5.0.1 相比有很多代码方面上的改进,比如抛弃 Desiger,分类源文件等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
-----------------------------------------------------------------------------------------------------------------------------------
File blank comment code
-----------------------------------------------------------------------------------------------------------------------------------
.\PlainCEETimer\UI\Forms\SettingsForm.cs 110 0 739
.\PlainCEETimer\UI\Forms\MainForm.cs 97 10 672
.\PlainCEETimer\UI\Controls\AppForm.cs 69 63 319
.\PlainCEETimer\UI\Controls\ListViewDialog.cs 52 18 282
.\PlainCEETimer\Modules\App.cs 29 5 226
.\PlainCEETimer\UI\Dialogs\ConsoleWindow.cs 26 0 225
.\PlainCEETimer\UI\Dialogs\RuleDialog.cs 34 0 223
.\PlainCEETimer\Interop\CommonDialogHelper.cs 51 0 217
.\PlainCEETimer\UI\ControlBuilder.cs 31 0 162
.\PlainCEETimer\UI\Forms\DownloaderForm.cs 20 0 160
.\PlainCEETimer\UI\Dialogs\ExamInfoDialog.cs 18 0 123
.\PlainCEETimer\UI\Controls\ColorBlock.cs 23 0 122
.\PlainCEETimer\UI\Controls\PlainListView.cs 29 6 121
.\PlainCEETimer\UI\Dialogs\CustomTextDialog.cs 18 0 120
.\PlainCEETimer\Interop\Natives.cs 25 0 115
.\PlainCEETimer\Modules\Startup.cs 17 7 115
.\PlainCEETimer\Modules\Configuration\ConfigObject.cs 19 0 108
.\PlainCEETimer\Modules\Validator.cs 23 12 106
.\PlainCEETimer\Modules\OptimizationHelper.cs 15 0 105
.\PlainCEETimer\Modules\Configuration\ExamInfoObject.cs 21 5 96
.\PlainCEETimer\UI\Forms\ScreenColorPicker.cs 12 0 89
.\PlainCEETimer.Natives\DisplayHelper\DisplayHelper.cpp 17 0 88
.\PlainCEETimer\Modules\ProcessHelper.cs 16 5 88
.\PlainCEETimer\UI\Dialogs\AppMessageBox.cs 14 0 86
.\PlainCEETimer\Interop\ThemeManager.cs 21 9 81
.\PlainCEETimer\UI\Enums.cs 11 12 75
.\PlainCEETimer.Natives\TaskScheduler\TaskScheduler.cpp 10 0 70
.\PlainCEETimer\Modules\Http\Downloader.cs 7 0 69
.\PlainCEETimer\UI\Forms\AboutForm.cs 8 0 68
.\PlainCEETimer\UI\Controls\NavigationBar.cs 10 4 63
.\PlainCEETimer\UI\MessageBoxHelper.cs 24 16 63
.\PlainCEETimer.Natives\ThemeManager\ThemeManager.cpp 28 18 62
.\PlainCEETimer\Modules\Updater.cs 7 0 62
.\PlainCEETimer\UI\ListViewItemSet.cs 14 0 60
.\PlainCEETimer\UI\Dialogs\RulesManager.cs 8 0 55
.\PlainCEETimer\Modules\JsonConverters\CustomRulesConverter.cs 9 0 52
.\PlainCEETimer\Modules\Configuration\CustomRuleObject.cs 12 0 50
.\PlainCEETimer\UI\Controls\AppDialog.cs 9 0 49
.\PlainCEETimer\UI\Controls\PlainColorDialog.cs 7 0 47
.\PlainCEETimer\Modules\RegistryHelper.cs 10 0 46
.\PlainCEETimer\Modules\UacHelper.cs 14 7 46
.\PlainCEETimer\Modules\Configuration\DefaultValues.cs 7 0 45
.\PlainCEETimer\Interop\Win32User.cs 17 8 44
.\PlainCEETimer\Modules\Configuration\DisplayObject.cs 11 0 43
.\PlainCEETimer\UI\PlainButtonBase.cs 6 0 41
.\PlainCEETimer\Interop\DisplayHelper.cs 10 0 40
.\PlainCEETimer\UI\Controls\PlainComboBox.cs 13 7 40
.\PlainCEETimer.Natives\TaskbarProgress\TaskbarProgress.cpp 10 7 39
.\PlainCEETimer\UI\ContextMenuBuilder.cs 7 0 39
.\PlainCEETimer\UI\Dialogs\ExamInfoManager.cs 8 0 39
.\PlainCEETimer\UI\Controls\PlainGroupBox.cs 4 6 35
.\PlainCEETimer\Modules\Enums.cs 3 0 34
.\PlainCEETimer\Modules\Configuration\ConfigHandler.cs 4 0 33
.\PlainCEETimer\Interop\MemoryCleaner.cs 7 0 31
.\PlainCEETimer\UI\Controls\PlainButton.cs 5 0 31
.\PlainCEETimer\UI\Controls\PlainFontDialog.cs 4 0 31
.\PlainCEETimer\UI\Controls\PlainNumericUpDown.cs 4 0 30
.\PlainCEETimer\Modules\JsonConverters\ColorSetConverter.cs 5 0 28
.\PlainCEETimer\UI\Controls\PlainTextBox.cs 4 0 27
.\PlainCEETimer\Modules\Extensions\Extensions.cs 14 10 26
.\PlainCEETimer\Modules\Xml.cs 5 0 26
.\PlainCEETimer\Modules\Configuration\ColorSetObject.cs 5 0 25
.\PlainCEETimer\Modules\JsonConverters\FontFormatConverter.cs 4 0 25
.\PlainCEETimer\Modules\Constants.cs 0 0 24
.\PlainCEETimer\Modules\Http\HttpService.cs 4 0 23
.\PlainCEETimer\UI\Extensions.cs 3 0 23
.\PlainCEETimer\Modules\JsonConverters\PointFormatConverter.cs 4 0 22
.\PlainCEETimer\Interop\IconHelper.cs 6 5 21
.\PlainCEETimer\Interop\Win32TaskScheduler.cs 6 0 20
.\PlainCEETimer\Modules\JsonConverters\CustomColorsConverter.cs 2 0 18
.\PlainCEETimer\Modules\Configuration\GeneralObject.cs 7 0 17
.\PlainCEETimer\Interop\TaskbarProgress.cs 4 0 16
.\PlainCEETimer\Modules\ResponseObject.cs 4 0 16
.\PlainCEETimer\UI\Controls\NavigationPage.cs 2 0 16
.\PlainCEETimer\UI\Controls\PlainLinkLabel.cs 1 0 16
.\PlainCEETimer.Natives\MemoryCleaner\MemoryCleaner.cpp 8 5 15
.\PlainCEETimer\UI\Controls\Hyperlink.cs 2 0 14
.\PlainCEETimer\Interop\ListViewHelper.cs 2 0 13
.\PlainCEETimer\Modules\WindowsBuilds.cs 0 0 13
.\PlainCEETimer\Program.cs 1 0 13
.\PlainCEETimer\Interop\RoundCorner.cs 2 0 12
.\PlainCEETimer\Properties\AssemblyInfo.cs 1 0 12
.\PlainCEETimer\UI\Controls\PlainLabel.cs 1 0 12
.\PlainCEETimer.Natives\RoundCorner\RoundCorner.cpp 7 7 11
.\PlainCEETimer\Modules\JsonConverters\ExamTimeConverter.cs 1 0 11
.\PlainCEETimer\UI\Controls\PlainCheckBox.cs 1 0 11
.\PlainCEETimer\UI\Controls\PlainRadioButton.cs 1 0 11
.\PlainCEETimer\Modules\Http\DownloadReport.cs 0 0 10
.\PlainCEETimer\UI\IListViewSubDialog.cs 1 0 10
.\PlainCEETimer\UI\ComboData.cs 0 0 8
.\PlainCEETimer\UI\IListViewData.cs 1 0 8
.\PlainCEETimer.Natives\ListViewHelper\ListViewHelper.cpp 5 5 6
.\PlainCEETimer\obj\x64\Release\.NETFramework,Version=v4.8.AssemblyAttributes.cs 0 1 3
.\PlainCEETimer.Natives\pch.cpp 0 0 1
-----------------------------------------------------------------------------------------------------------------------------------
SUM: 1229 258 6903
-----------------------------------------------------------------------------------------------------------------------------------

共 6903 行。

为什么不用 WPF 开发

接下来我的回答可能会得罪学过 WPF 人,但我并没有任何歧视,只是吐槽一下罢了,请酌情阅读。主要是以下三个方面。简单来说就是高考倒计时的开发用 WinForms 足够了。但无论怎么说,如果以后我还会开发新项目,肯定会根据具体需求优先考虑是否使用 WPF,毕竟有些功能用 WPF 实现也是挺方便的。

WPF 资源占用肯定比 WinForms 高

虽然 WPF 渲染使用的是 GPU (DirectX),在各种动画绘制的精美程度上秒杀使用 CPU (GDI+) 的 WinForms。但高考倒计时不需要这些,Win32 原生动画也不是不能接受。除了动画方面,也就是运行时性能了。(以下数据来自 System Informer) 目前高考倒计时运行时内存占用可控制在 20 MB 以内 (未开启自动清理),待机时 CPU 平均占用也不会超出 0.1 %,这样的性能 WPF 不一定做得到。不过在科技越来越发达的今天,个人电脑的配置也越来越高,似乎也可以接受较高的占用。不过我倒是一向追求轻量、简洁,能少占用点就少点。

WPF 原生界面元素没有 WinForms 好看,尽管其可定制性很高

原生 UI 元素默认外观的简陋是我放弃 WPF 的原因之一,这意味着我必须得自行编写许多模板,或者直接安装第三方 UI 库。这样的话程序的体积将大大增加,体积估计至少 1 MB 起步,其中至少 90% 的体积都花在 UI 上了,得不偿失。使用 WinForms 开发,主程序体积才 160+ KB,算上 JSON .NET 库等一共也就 800+ KB,压缩后安装程序体积也才 330+ KB。但不得不说 WPF 在 UI 方面确实挺好的,以至于有的时候我也对它心动,只是在高考倒计时里用不上罢了。

WPF 给我一种把简单问题复杂化的感觉

那无非就是各种绑定了,好处就是 UI 与业务解耦 (MVVM),坏处就是画蛇添足。为什么不以 WinForms 的直接访问 UI 和 事件驱动为主?其实仔细想想还是可以理解,两者都拥有一个消息循环,最大的区别在于 WinForms 对每一个控件都有一个 WndProc;而 WPF 只有窗口框架那一个 WndProc,UI 元素的运行全靠这个顶级 WndProc 和 WPF 自己的一些机制来完成。所以 WPF 这种新架构可以说就是量身为 MVVM 打造的,两者有优也有劣吧。尽管在 WPF 中也可以完全像 WinForms 那样直接访问 UI 和事件驱动,但这也并非其设计初衷,反而倒不如直接用 WinForms。如果你问我小白入门 C# 学 WinForms 还是 WPF,我只能说如同驾照考 C1 还是 C2 一样,你细品。请结合自己的喜好来做决定。

为什么这么执着于高考倒计时

提出编写高考倒计时的人来自我高中时期班上一位同学,是她才让高考倒计时有了今天,虽然在她看来她可能只是随口一说,但在我看来,这是一次深入 C# 编程领域绝佳时机。在此非常感谢这位同学给我的星星之火,为了不让它熄灭,我将坚持把高考倒计时做到最好。今天,我达成了这个目标,但并不意味着高考倒计时的更新会就此停止,一旦有时间,我也会打开代码看上几眼,找出其中的瑕疵与不足。如果你在提交记录中看到诸如 “整理了一些代码” “清理代码” 之类的字样说明我来找茬了,这些瑕疵只能在这种时候发现,在开发时根本察觉不到。

高考倒计时的奇葩用法

本高考倒计时支持对考试名称、日期时间的完全自定义。这意味着高考倒计时不再局限于 “高考”,任何考试都可以。另外只要你有创意,你还可以把一些奇怪的东西用来进行倒计时:

你以为这样就完了吗?如果你觉得 “距离xx…x天x时x分x秒” 的内容有点无聊,你还可以自定义倒计时内容的格式,需要用到特定的占位符,详见全局自定义文本对话框或者是用户手册的 ✨ 占位符一览。在 设置>显示 的规则管理器中,你可以设置不同时刻要显示的倒计时内容:

不过若你不需要不同时刻显示不同的内容的话,你可以不用设置规则,直接去设置全局自定义文本:

更多相关详细教程推荐大家去看看 📢 用户手册,里面包含了几乎所有有关本程序的使用说明、特性等。

高考倒计时的价值远不止高考倒计时

如题,我觉得高考倒计时的价值远不止高考倒计时,甚至它可以不用叫 “高考倒计时” 了。它所体现的的价值更多在于编程的素养,比较偏向于底层,有很多值得初学者学习的地方。欢迎访问源代码,互相交流与学习。


【PlainCEETimer】两年了,分享一下开发感受
https://wanghaonie.github.io/posts/07076c71374b/
作者
WangHaonie
发布于
2025-05-11 09:40:46
更新于
2025-07-28 22:54:41
许可协议