余弦G的博客
type: channel
link: https://www.cosineg.com/
items: DeepWiki-Open 部署指南
items: 实现基于 ASR + LLM + TTS 的智能语音助手 - 小「埃」同学
items: 女神异闻录3 Reload 通关随笔🌕
items: ASP.NET Core 实现 SSE 流式响应
items: ChaosBlade入门使用简介
items: Effective C# 阅读笔记（四）
items: 稍稍水一下
items: 洛天依十周年生日快乐🎂
items: 今夕是何年
items: Effective C# 阅读笔记（三）

DeepWiki-Open 部署指南
type: item
date: 2025-08-16T16:31:00+08:00
description: 前言现在 AI 编程工具已经很常见了，像 Cursor、Trae、Copilot、Kiro 这些我都陆续试过，体验都还不错。不过能帮忙解读整个代码仓库的，目前来看 DeepWiki 算是比较独特的。刚看到这个功能的时候觉得挺实用。不过 DeepWiki 只能解析开源项目，私有项目就需要付费或者自己找解决办法了。我最开始试的是国人开发的 OpenDeepWiki，但部署起来遇到了不少问题，最后还是放弃了。后来又找到了 DeepWiki-Open，经过一番折腾终于跑起来了。现在网上相关资料比较少，所以写一下自己的部署流程，供大家参考。准备文件这部分应该是最麻烦的，而且要自己摸索。官方 Readme 提供了两种部署方式：可以用 Docker 一键启动整个服务，也可以分别在本地启动前后端。我这里选择了 Docker 部署。不管用哪种方式，第一步都是先把仓库拉下来。git clone https://github.com/AsyncFuncAI/deepwiki-open.git cd deepwiki-open接下来，需要在文件夹下创建一个 .env 配置文件，主要填写你使用的大模型和 embedding 模型的 API 地址和 key。我这里用的是 AzureOpenAI 和其他家的 embedding 模型。注意，一定要配置 embedding 模型的地址，而且要填在 OpenAI 的配置项里，否则后面会报错。# 我这里用的 Azure，请根据官方文档选择成自己用的服务商 AZURE_OPENAI_API_KEY=tomorin AZURE_OPENAI_ENDPOINT=https://anon.openai.azure.com/ AZURE_OPENAI_VERSION=2025-01-01-preview # 这里主要配置 embedding 模型。如果你的大模型和 embedding 模型都用的是同一家支持 OpenAI 兼容 API 的服务商，只需要填这一部分，就可以同时用他们的大模型和 embedding 服务了。 OPENAI_API_KEY=tomorin OPENAI_BASE_URL=https://api.anon.com/v1保存成 .env 文件。为了速度，我们可以修改一下 Dockerfile。npm 我们可以使用镜像：RUN npm ci --legacy-peer-deps # 改成 RUN npm ci --legacy-peer-deps --registry=https://registry.npmmirror.comapt 也可以用镜像（大部分能走）：# Install Node.js and npm # 下面部分修改成 RUN echo "deb http://mirrors.aliyun.com/debian/ bookworm main contrib non-free non-free-firmware\n\ deb http://mirrors.aliyun.com/debian-security bookworm-security main contrib non-free non-free-firmware\n\ deb http://mirrors.aliyun.com/debian-security trixie-security main contrib non-free non-free-firmware\n\ deb http://mirrors.aliyun.com/debian/ bookworm-updates main contrib non-free non-free-firmware\n\ deb http://mirrors.aliyun.com/debian/ trixie main contrib non-free non-free-firmware\n\ deb http://mirrors.aliyun.com/debian/ bookworm-backports main contrib non-free non-free-firmware" \ > /etc/apt/sources.list && \ apt-get clean && \ apt-get update && \ apt-get install -y \ curl \ gnupg \ git \ ca-certificates && \ mkdir -p /etc/apt/keyrings && \ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /e…

实现基于 ASR + LLM + TTS 的智能语音助手 - 小「埃」同学
type: item
date: 2025-02-11T20:30:00+08:00
description: 前言因为最近在公司做大模型相关的工作，前段时间就趁着兴头，挑了点空闲时间按照自己瞎想的思路实现了一个埃癸斯的语音助手DEMO（可能也不算助手吧，算是角色扮演？）.先前演示和代码都已经放在B站和GitHub上了，就顺带也放到博客来吧。视频演示https://www.bilibili.com/video/BV1Dyf5YLE4p代码仓库https://github.com/CosineG/aegis-assistant系统介绍系统工作流程语音活动检测（VAD）：通过声音活动实时检测用户语音输入音频采集：触发录音模块进行语音捕获语音识别（ASR）：将音频转换为文本大模型处理（LLM）：解析用户意图并生成回复语音合成（TTS）：将文本回复转换为语音输出当前为循环对话模式，即程序启动后持续监听环境语音。模型选用语音识别采用 fast-whisper large-v3 模型，多语言支持、识别准确率高。大模型交互选用 Deepseek V3 的官方 API（性价比高，但是现在因为 R1 爆火很不稳定）。另外实现了：流式输出：通过分块响应降低等待延迟。Function Calling：支持天气查询、音乐播放等扩展功能（需自定义实现）。语音合成选用GPT-SOVTIS（基于P3R解包语音数据集训练），在 RTX 4080 环境下训练和推理速度都很优异，相比下 Fish-Speech 训练周期较长，生成质量不佳。针对长文本场景的语音延迟问题，采用分句级流式处理方案：实时解析大模型流式输出，动态检测完整语义分句，后台线程并行生成语音,最终实现播放与生成的流水线作业。可在播放当前语句时即可预生成后续内容，显著提升交互流畅度。扩展方向智能家居集成：通过米家 Python SDK 实现设备控制。离线部署优化：部署如 Qwen 2.5 14B 等大模型本地交互。

女神异闻录3 Reload 通关随笔🌕
type: item
date: 2024-12-31T21:47:00+08:00
description: [scode type="red"]严重剧透警告！[/scode]前言年底了，这段时间玩了100个小时的一周目本篇+埃癸斯篇。但苦于没有人能分享，很想写点东西表达自己对这款游戏的喜爱。毕竟通关的时候可是哭了很久。感想之前只在2016年接触过P5无印版，那时候就被P5的视觉风格和音乐深深震撼。很早就知道了P3R，但直到11月才入手，主要也是担心大家吐槽的爬塔无聊之类的问题（毕竟刚开始也挺贵的）。结果开玩以后发现完全多虑了，P3R就是特别对我的电波。主色调是我最喜欢的蓝色，艺术风格依旧潮到出水，音乐更是无敌。第一次踏入校园，樱花飘落，听到 Want To Be Close 感觉被直击心灵。而夜晚降临，总会想要在购物中心把 Color Your Night 听完一遍，再开始行动。战斗曲 Mass Destruction 和 It's Going Down Now 都酷到不行。虽然有人觉得日常剧情平淡如水，但我却觉得这些温馨的日常特别宝贵，还有海滩搭讪、休学旅行等愉快时光引人发笑。尤其是到了最后情况急转直下，几乎断崖式的崩盘，整个画面被蒙上惨白的滤镜，再看那些日常瞬间变成了遥不可及的珍贵回忆。[hplayer][Music server="netease" id="2123807711" type="song"/][/hplayer][hplayer][Music server="netease" id="2123807718" type="song"/][/hplayer]真的特别喜欢埃癸斯。看着埃癸斯从原始如机器的呆板木讷，只是不知为何地执着守护理。到后来逐渐拥有情感，开始思考探索生命，却痛苦起自己为何是非生命的机器。到最终真正敢于向理表达自己真挚而热烈的爱意。玩到毕业典礼到天台那段，我眼泪刷得就下来了，听着小埃深情的独白，明明她终于明白了活着的意义，发誓守护理到最后，以为理只是累了让他休息，可玩家知道理已经是最后回光返照了。最后你的记忆一响我更是哭到身体发麻，不能自已。[hplayer][Music server="netease" id="2123802258" type="song"/][/hplayer]在后日谈中，看似大家已接受了现实，实则每个人都在心底挣扎，被深埋的情感所困。其实玩到中期就大概能看得出来，墨提斯就是埃癸斯的那个，不愿被留下孤身一人，渴望守护最爱的最重要的人到最后，结果绝望到哭泣，宁愿舍弃生命的那个自己。 ::aru:crying:: [hplayer][Music server="netease" id="2610618701" type="song"/][/hplayer]就感觉实在太喜欢结城理和埃癸斯了，虽然缺憾的结局更深刻，但还是希望终有一天两人能够团聚吧。「不要哭」批评但是确实游戏有各种各样的问题吧，毕竟是老游戏的重制，很多地方几乎是没做现代的改造就原样端上来了。玩法部分就是传统女神异闻录那一套，但相比P5日常内容要贫瘠。社群质量参差不齐，个别实在是难以让人留下印象，而且到后面夜晚没事干，白天的社群却来不及做完。爬塔部分就更不用说了，老问题，开始还挺有兴趣探索，后来基本就是直奔宝箱、精英怪和下一层。很喜欢埃癸斯，但是塑造过于后期，7月加入，11月逐渐开始有重要剧情，但12月整个缺席，剩下根本没多少时间了。后日谈的游戏体验更是让人头疼，本来本篇日常+爬塔还算能中和游玩体验，但纯爬塔的后日谈真的让人难以坚持，直到最后剧情才开始爆发，但估计很多人撑不到那个时候。剧情上，由加莉想回到过去我能理解，但学姐的选择我觉得OOC了，她应该是最不可能选择回去的人。结语P3R好玩，结城理好帅，我爱埃癸斯。

ASP.NET Core 实现 SSE 流式响应
type: item
date: 2024-09-10T21:45:17+08:00
description: 重点先说一个踩过的坑：如果要使用 SSE 流式响应，那么在 Nginx 里不要开启该接口的 Gzip ！！！因为开启 Gzip 后会导致数据达到一定大小才会被压缩然后返回给前端，导致前端不能实时获得数据，就无法形成流式的文本效果。例子举个在 ASP.NET Core 中实现 SSE 流式响应的简单例子。[HttpGet] public async Task<IActionResult> SseExample() { // 请求头 Response.Headers.Add("Content-Type", "text/event-stream"); Response.Headers.Add("Cache-Control", "no-cache"); Response.Headers.Add("Connection", "keep-alive"); // 假设不断得到新数据 for (int i = 0; i < 10; i++) { // 每个数据参照 SSE 返回数据格式进行组装 var content = "event: message\n" + "data: {\"color\":\"66ccff\"}\n\n"; // 立刻写入响应 await Response.WriteAsync(content); await Response.Body.FlushAsync(); } // 结束 return new EmptyResult(); }测试的时候可以从控制台的网络详情里看到本次响应的数据流：备注我目前主要是希望搭一套向量知识库（选了MaxKB），查询出知识库中的已知信息然后利用大模型分析回答。因为需要对知识库的输入做处理（比如增加关键字，过滤某些信息，相同问题查缓存等），直接暴露知识库 API 风险较高，可能 token 都被人用来问大模型其他问题了，因此需要做一层处理和转发。而当前后端是基于 ASP.NET Core 的，所以需要在 ASP.NET Core 里实现 SSE 流式响应，使得能够在前端展示一个字一个字蹦出来的效果。

ChaosBlade入门使用简介
type: item
date: 2024-06-15T16:58:00+08:00
description: 前言还是想着写一篇技术相关的文章吧，不然显得我的博客完全没有意义了 ::aru:lurking:: 这次简单介绍一下混沌工程相关的 ChaosBlade 工具，因为我也是刚接触不久，希望能帮助到需要入门的同学，也请大佬在评论里指点赐教。混沌工程什么是混沌工程呢？美团技术博客最近刚好有一篇相关的文章：超大规模数据库集群保稳系列之二：数据库攻防演练建设实践。其中是这么介绍的：简单而言，混沌工程是在系统上进行实验的技术手段，目的是建立对系统抵御生产环境中失控条件的能力以及信心。这主要体现在两个方面，从系统角度来讲，混沌工程可以提升我们架构的容错能力和韧性，降低故障发生率和复发率，提升系统用户在使用时的体验；从人员角度来讲，通过混沌工程我们可以加深对架构的理解，在处理故障时能提高整体的应急效率，并且能主动去探究系统中潜在的一些问题。我的理解就是简单来说，用来提前做故障演练发现隐藏问题的。所以我们需要这么一个工具来实现这件事情，因此我们可以选择ChaosBlade。ChaosBlade介绍ChaosBlade 是阿里巴巴开源的一款遵循混沌工程原理和混沌实验模型的实验注入工具，帮助企业提升分布式系统的容错能力，并且在企业上云或往云原生系统迁移过程中业务连续性保障。它支持注入系统资源（仅Linux系统）和Java应用级别的异常。系统资源异常包括：• 硬件（CPU负载、内存负载、磁盘填充、磁盘IO负载）• 文件（文件新增、文件追加、文件移动、文件删除、文件权限变更）• 网络（网络延迟、网络丢包、网络DNS异常、网络占用）• 进程（进程挂起、进程杀死）Java应用异常包括：• OOM（内存溢出）• 延迟（方法调用延迟、HTTP请求延迟、Dubbo rpc调用延迟等）• 抛异常（方法调用异常、HTTP请求异常、Dubbo rpc调用异常等）• 返回值篡改（基础类型和 null）• 执行自定义脚本（在注入方法的前或后执行自定义脚本）更多的介绍可以看中文版介绍文档：ChaosBlade: 一个简单易用且功能强大的混沌实验实施工具。使用但我们这是入门向文章，所以主要还是面向使用。使用 ChaosBlade 主要通过本体命令行的方式，或者 ChaosBlade-Box 网页端进行操作。如果是 k8s 上部署的话也可以通过 operator 使用 yaml 文件来进行实验。我这里主要使用 ChaosBlade-Box，但是根本上是相通的，因为实验的参数配置都是一样的。而且目前不管是界面还是文档其实都不完善，界面上很多参数其实都没有具体说明，需要去看命令行的文档里的参数配置才知道具体用途，另外我也会把遇到的一些坑做一些说明。官方文档首先我先贴上官方文档，有两个：ChaosBlade 整体介绍 | ChaosBladeREADME | chaosblade-help-zh-CN不过当中很多内容是相同的，主要要看每个实验的配置参数部分。安装 ChaosBlade-Box首先看你是要在 k8s 集群中还是机器上安装：1、如果是 k8s 中，首先用 helm 安装一个 chaosblade-operatorhelm repo add chaosblade-io https://chaosblade-io.github.io/charts helm install chaosblade chaosblade-io/chaosblade-operator --namespace chaosblade然后安装 box，下载 Github Release 页里提供的 tgz 包，也用 helm 安装：# 下载（用 1.0.3 而不是 1.0.4 的原因是 github 上发布了 1.0.4 但是作者没把镜像传到 docker hub ……） wget https://github.com/chaosblade-io/chaosblade-box/releases/download/v1.0.3/chaosblade-box-1.0.3.tgz # 安装 helm install chaosblade-box chaosblade-box-1.0.3.tgz --namespace chaosblade --set spring.datasource.password=数据库密码其中 namespace 参数是你要安装的命名空间，记得先创建好。后面的参数是安装时，同时会部署一个 mysql 5.6 的 deployment，你需要为它的 root 账号设置密码。2、如果是在机器里安装，首先确保你有 java 1.8 的运行环境，以及 mysql。注意 mysql 有要求！如果是 5.7 直接使用即可，但更高版本必须关闭 ONLY_FULL_GROUP_BY 设置，否则后面使用…

Effective C# 阅读笔记（四）
type: item
date: 2023-05-16T23:29:00+08:00
description: 前言为了提升一下自己的姿势水平，买了 Effective C# 和 More Effective C# 两本书，想一边阅读一边强迫自己做点笔记（主要是自己的理解），不然怕是看了就忘。另外手头还有一本《深入解析C# ( C# in Depth )》其实我已经阅读了一遍，但感觉没咋读懂，下次有机会也用这种方式重读一遍。忙着搞秋招和毕业论文，以及自己是在是太能摸了，导致距离上次更新已经快一年了。不过以后工作还是要写.NET的，所以还是不能把相关学习落下，今天开始边写变更吧。今天这篇是 Effective C# 的第四章。第四章 合理地运用LINQLINQ全名Language Integrated Query，中文译为语言集成查询，简单来说就是用类似SQL语言的方式来对数据进行查询和操作，C#里提供了两种可使用的语法，分别是查询语法和方法语法。查询语法更贴近SQL语法，但其实我从来没写过...方法语法就是通过扩展方法实现了一系列方法，在数据集合之后调用，比如list.Where(n => n > 0).ToList();，我觉得使用起来更加方便，而且这个应该能算作是函数式编程吧。LINQ给数据操作还是带来了很大的方便的，尤其是写后端的时候操作数据库，像Java也是从8开始引进了stream，用起来感觉也很相似，之前实习的时候基本都是在写stream。第29条 优先考虑提供迭代器方法，而不要返回集合当我们要返回一系列对象的时候，应该优先考虑提供迭代器方法而不是集合，这样可以立刻返回，并且等调用方需要实际使用的时候才会创建对应数据，节省时间和空间（就是yield return返回IEnumerable<T>而不是直接返回一个List）。举个最简单的例子来说，我可能需要用到所有非负int值组成的序列中的一部分，如果直接创建一个包含这些数值的List<int>很划不来，而通过Enumerable.Range(0, int.MaxValue)会返回IEnumerable<int>，可以在后续使用的时候再去生成数值。而如果调用方真的需要对这些数据反复使用或者缓存下来，那让他们自己调用ToList()或者ToArray()就好了，相当于提供了两种选择，方便灵活使用，因此即使调用方确实需要把数据保存到集合里，我们还是应该优先提供迭代器方法（其实LINQ就是基于这个原则的）。另外在编写迭代器方法的时候要注意一个问题，就是参数检查和生成序列的逻辑分开写。因为如果合在一起的话：// 求正数序列 public static IEnumerable<int> GeneratePositiveNumber(int first) { // 参数检查 if (first <= 0) { throw new ArgumentException("first must be postive", nameof(first)); } // 序列生成 var num = first; while (num <= int.MaxValue) { yield return num; num++; } }如果按照上面这么写的话，当进行var nums = GeneratePositiveNumber(-11);的时候，并不会抛出异常，只有当真正使用到nums里面的数值的时候，才会抛异常，这样很不合理而且难以诊断错误。因为编译器固定如此，无法修改，但我们可以把检查和生成分成两段函数来规避这个问题，例如：// 求正数序列 public static IEnumerable<int> GeneratePositiveNumber(int first) { // 参数检查 if (first <= 0) { throw new ArgumentException("first must be postive", nameof(first)); } // 序列生成 return GeneratePositiveNumberImpl(first); } // 序列生成的实现 private static IEnumerable<int> GeneratePositiveNumberImpl(int first) { var num = first; while (num <= int.MaxValue) { yield return num; num++; } }这样的话，调用的时候，在进入到迭代器方法之前就能抛出异常。第30条 优先考虑通过查询语句来编写代码，而不要使用循环语句C#提供了经典的比如for、foreazh、while等循环结构，但他们的功能其实也可以通过查询语句来实现。与采用循环语句所编写的命令式结构相比，查询语句能够更为清晰地表现开发着的意图。比我想要打印一批成绩高于80分的…

稍稍水一下
type: item
date: 2022-11-28T10:57:00+08:00
description: 快半年销声匿迹了，还是来博客水一下好了（阅读笔记的坑还是后面再填吧XD ::aru:proud:: 暑假三个月在字节实习，感叹互联网福利好的同时也不得不说强度确实高，十点下班家常便饭。但考虑今年秋招形势异常险峻，本来还是想尽量转正留下，结果谁想到整个部门十来个实习生要争抢仅有的一两个坑位，只能重新开始刷题背八股准备秋招。但秋招难度也是相比去年骤然提升，说不好同一个人去年能进大厂，换今年得进电子厂::aru:lurking::。折腾了几个月，收获可以说是寥寥无几，还好最终（未来的）我司愿意收留我，而且是我梦寐以求的.NET岗，待遇也没有低Java岗一等，实在令人感激涕零。众人心心念念的矿难终于来了，本来是想着等工作了再换显卡，这下没忍住收了个自矿过的3070，性能比我原来的1660S直接高了一倍，只能说是很爽了。刚好又碰上AI绘画的风口，我也搞了份Stable Diffusion + 泄露的Novel AI模型玩了玩，不得不感慨效果是真的强大，可惜的是小众角色因为样本太少很难画得出来，像miku怎么都能出好图，天依的话指定luo tianyi, gray hair, green eyes这些prompt也出不来想要的效果。也尝试了用Textual Inversion自己训练天依的embedding，但是样本的画风和衣服也会被学习，导致效果很差，只能作罢。但是训练画风是真的很强，试了几个风格比较鲜明的画师的样本，出的图明显就有对应画师的感觉（虽然也可以吐槽是出的图都变成固定的那几个女演员）。本来我的Pico Neo 3只能用来打打乒乓球，官方串流真的很烂，谁知道Pico 4一出，有了Vitural Desktop串流，我立马照教程切了外区买了一份VD。尝试用VD串流玩了一下半条命Alyx，确实基本感觉不到延迟，而且不得不说V社还是强啊，Alyx真正给我了一种这就是未来的游戏的感觉，只是现阶段VR设备续航是真的不行，还有眼睛很容易疲劳，玩一个多两个小时不到就撑不住了。最后秀一下买的天依的景品手办，我最喜欢的还是公式服，可惜就是不出普通的比例模型，只有景品，之前第一次出货还因为太过邪神召回重做了。十周年CD也到手了，可惜手头没有光驱，一时半会拷不出来::aru:knife::

洛天依十周年生日快乐🎂
type: item
date: 2022-07-12T21:45:06+08:00
description: 时间过得超快，居然已经听了天依九年了。上B站追着洛天依新曲排行榜，往mp3里使劲拷歌，给喜欢的女孩子分享阿良良老师的I LOVE U，攒钱买的第一张专是平3，穿着纯蓝色带V3声库封面立绘勾线的萌X家的T恤参加考试，为了天依学吉他学画画（虽然都没学会😭…现在还能记得当初在b站上看到过的一个视频，是用miku的演唱会改了天依的模型，唱着心印。觉得演唱会是遥不可及的梦，没想到几年后却真的能去线下打call到浑身发抖。中场天依给全场问好的时候，没听清是先问的女生，迫不及待地大声回应，回过神来发现旁边的人都在笑😂。经历过VC博歌乐到VOCANESE那段艰难的时期，也经过Vsinger之后逐渐火热的圈子，真的是好长好长一段日子了。最近两年新歌听得少了，但前段时间听到AI依的声音我还是哭了（尤其还是翻唱那些经典老歌），那些心跳同步的时光重新涌上心头。天依十周年生日快乐🎉！

今夕是何年
type: item
date: 2022-05-09T23:12:00+08:00
description: 天依新AI声库+经典老歌，成功把我听哭了。真好啊。真好啊。[vplayer status="true"][Video url="https://www.bilibili.com/video/BV1Zv4y1K74L" title="心印" /][Video url="https://www.bilibili.com/video/BV1tY4y1b7Vr" title="Feel Your Dream" /][Video url="https://www.bilibili.com/video/BV12r4y187dd" title="前尘如梦" /][Video url="https://www.bilibili.com/video/BV13Z4y187ra" title="66CCFF" /][Video url="https://www.bilibili.com/video/BV1j34y1h7aC" title="牵一半" /][/vplayer]我现在只有一个心愿就是立马听到AI声库版的I lOVE U！！

Effective C# 阅读笔记（三）
type: item
date: 2022-05-09T16:07:22+08:00
description: 前言为了提升一下自己的姿势水平，买了 Effective C# 和 More Effective C# 两本书，想一边阅读一边强迫自己做点笔记（主要是自己的理解），不然怕是看了就忘。另外手头还有一本《深入解析C# ( C# in Depth )》其实我已经阅读了一遍，但感觉没咋读懂，下次有机会也用这种方式重读一遍。之前为了找实习（今年真难啊），花了很多时间在了刷LeetCode和背八股文上。现在离去实习也没多久了，啥也不会过去不太好，所以后续应该也要花相当时间在学Java上。今天这篇是 Effective C# 的第三章。第三章 合理地运用泛型泛型还是一个比较方便和重要的特性。Java的泛型基于类型擦除，也就是编译器会保证类型安全，但实际运行时类型都被擦除了，所有不同List<T>都是同一个类型List（个人的理解，有错误请务必指出）。而C#的泛型则是真正的泛型类型，比如通过typeof(List<int>)可以看到其运行时类型System.Collections.Generic.List`1[System.Int32]。而这些泛型类只有在运行时碰到了，CLR才会将其实例化，可以避免不必要的开销。另外值类型和引用类型分别作为类型参数的泛型类也不相同。泛型参数包含值类型时，CLR在JIT时都会生成单独特化的代码，不同泛型类之间不共享代码。这样能够防止值类型的装箱和拆箱问题。而对于引用类型，CLR生成的不同泛型类的代码是共享的，类型安全通过编译器在编译时保证（但我觉得即使生成的代码相同，也应该还另外保存了类型信息，因为typeof()是可以看到运行时泛型类中的泛型参数究竟是什么引用类型的，这一块书上没说），这样可以缩减程序尺寸和提升性能。第18条 只定义刚好够用的约束条件给泛型的类型参数指定约束条件，这样只有满足特定条件的类型才能作为该泛型的参数。约束条件具体都包括哪些，请参考文档 类型参数的约束（C# 编程指南）（中文版在表格的倒数第2-5行有显示错误，英文版没问题，分别应该是基类名和接口名）。书中主要是约束条件限制得太宽，那就很难使用，因为缺少信息，很多操作不能使用，比如public static bool AreEqual<T>(T left, T right) where T : IEquatable<T> { return left.Equals(right) }如果设定了IEquatable<T>的约束条件，那么在内部对于T类型的变量就可以使用IEquatable<T>.Equals()，否则就只能调用Object.Equals()。同样，如果设置得过严，那就失去了泛型的优势，比如：// 我想的一个例子，实际上不太合理，但用来说明应该足够了 static void Print<T>(T list) where T: IList<int> { foreach (var item in list) { Console.WriteLine(item + 1); } }HashSet<int>对象按理说应该也能完成上面循环输出的操作，但实际上却无法使用，因为HashSet<int>并没有实现IList<int>接口。而foreach操作只要实现了IEnumerable<T>就能使用，因此把IList<int>约束换为IEnumerable<int>更加合理。另外书中提醒还有new()约束也要注意使用，因为有的时候代码中的new()可以用default()替代。其中对于值类型，new()返回的就是值类型的默认值，所以和default()没区别（注意C# 10开始支持自定义struct的无参构造函数，对于这样的struct，new()和default()就不同了！）；对于引用类型，默认值都是null，显然new()和default()和差异很大。总的来说，泛型就是为了在各种场合能够广泛使用，所以要仔细考虑约束条件。约束条件太宽，有很多特性难以使用；约束条件太严，使用场合就受限。因此要仔细考虑每一条约束条件，只保留必要的条件。第19条 通过运行期类型检查实现特定的泛型算法放宽类型参数的限制（比如让输入参数的类型为接口，而非一个具体类型），可以让程序更加通用和泛化，但是这又会导致实现的时候无法使用一些具体类型才拥有的特性。因此可以通过运行期类型检查来检测参数的运行时类型，如果是一些特定类型则使用其的某些特性，以此达到提升程序性能的目的。书中举了个作者自己写的例子，但我觉得直接看List<T>的源码就好，List<T>有一个参数为IEnumerable<T>类型的构造函数：public List(IEnumerable<T> collection) { if (collection == null) ThrowHelper.ThrowA…