diff --git "a/Doc/Cron\350\241\250\350\276\276\345\274\217.md" "b/Doc/Cron\350\241\250\350\276\276\345\274\217.md"
index eb96445..6661b38 100644
--- "a/Doc/Cron\350\241\250\350\276\276\345\274\217.md"
+++ "b/Doc/Cron\350\241\250\350\276\276\345\274\217.md"
@@ -1,415 +1,415 @@
-# Cron����ʽ
+# Cron表达式
-## ����
+## 概述
-`NewLife.Threading.Cron` ��һ���������� Cron ����ʽ������ƥ�����������ж�ij��ʱ����Ƿ���������ܼ�����һ��/��һ�ε�ִ��ʱ�䡣
+`NewLife.Threading.Cron` 是一个轻量级的 Cron 表达式解析和匹配器,用于判断某个时间点是否满足规则,并能计算下一次/上一次的执行时间。
-��� Cron ��ȣ�NewLife.Cron ����������࣬�ʺ��ڶ�ʱ������ϵͳ��ʹ�á�
+与标准 Cron 相比,NewLife.Cron 更加轻量简洁,适合在定时任务、调度系统中使用。
-**�����ռ�**: `NewLife.Threading`
-**Դ��**: [NewLife.Core/Threading/Cron.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/Cron.cs)
+**命名空间**: `NewLife.Threading`
+**源码**: [NewLife.Core/Threading/Cron.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/Cron.cs)
---
-## ��������
+## 快速入门
-### �����ͽ���
+### 创建和解析
```csharp
using NewLife.Threading;
-// ��ʽ1������ʱ�������ʽ
+// 方式1:构造时传入表达式
var cron = new Cron("0 0 2 * * 1-5");
-// ��ʽ2���ȴ��������
+// 方式2:先创建后解析
var cron2 = new Cron();
cron2.Parse("*/5 * * * * *");
```
-### �ж�ʱ���Ƿ�ƥ��
+### 判断时间是否匹配
```csharp
-var cron = new Cron("0 0 2 * * 1-5"); // ÿ���������賿2��
+var cron = new Cron("0 0 2 * * 1-5"); // 每个工作日凌晨2点
-// �жϵ�ǰʱ���Ƿ���ϱ���ʽ
+// 判断当前时间是否符合表达式
if (cron.IsTime(DateTime.Now))
{
- Console.WriteLine("������ִ��ʱ��");
+ Console.WriteLine("现在是执行时间");
}
-// �ж��ض�ʱ��
-var time = new DateTime(2025, 1, 6, 2, 0, 0); // 2025��1��6��(��һ) 2��
+// 判断特定时间
+var time = new DateTime(2025, 1, 6, 2, 0, 0); // 2025年1月6日(周一) 2点
if (cron.IsTime(time))
{
- Console.WriteLine("��ʱ�����Ϲ���");
+ Console.WriteLine("该时间点符合规则");
}
```
-### ������һ��ִ��ʱ��
+### 计算下一次执行时间
```csharp
-var cron = new Cron("0 0 2 * * *"); // ÿ���賿2��
+var cron = new Cron("0 0 2 * * *"); // 每天凌晨2点
var next = cron.GetNext(DateTime.Now);
-Console.WriteLine($"��һ��ִ��ʱ�䣺{next}");
+Console.WriteLine($"下一次执行时间:{next}");
-// ������һ��ִ��ʱ��
+// 计算上一次执行时间
var prev = cron.GetPrevious(DateTime.Now);
-Console.WriteLine($"��һ��ִ��ʱ�䣺{prev}");
+Console.WriteLine($"上一次执行时间:{prev}");
```
---
-## ����ʽ�
+## 表达式语法
-### ����ʽ�ṹ
+### 表达式结构
-Cron ����ʽ�ɿո�ָ��� **6 ���ֶ�**��ɣ���7���ֶ�"��"�ݲ�֧�֣���
+Cron 表达式由空格分隔的 **6 个字段**组成(第7个字段"年"暂不支持):
```
-�� �� ʱ �� �� ����
+秒 分 时 日 月 星期
```
-| �ֶ� | ��Χ | ˵�� |
+| 字段 | 范围 | 说明 |
|-----|------|------|
-| �� | 0-59 | ���� |
-| �� | 0-59 | ������ |
-| ʱ | 0-23 | Сʱ����24Сʱ�ƣ� |
-| �� | 1-31 | ÿ�µĵڼ��� |
-| �� | 1-12 | �·� |
-| ���� | 0-6 | ���ڼ���0=���գ�1=��һ��...��6=������ |
+| 秒 | 0-59 | 秒数 |
+| 分 | 0-59 | 分钟数 |
+| 时 | 0-23 | 小时数(24小时制) |
+| 日 | 1-31 | 每月的第几天 |
+| 月 | 1-12 | 月份 |
+| 星期 | 0-6 | 星期几(0=周日,1=周一,...,6=周六) |
-**ʾ��**��
+**示例**:
```
-0 30 8 * * 1-5 // ÿ�������� 8:30
-0 0 */2 * * * // ÿ2Сʱ����
-0 0 0 1 * * // ÿ��1���賿
-*/10 * * * * * // ÿ10��
+0 30 8 * * 1-5 // 每个工作日 8:30
+0 0 */2 * * * // 每2小时整点
+0 0 0 1 * * // 每月1号凌晨
+*/10 * * * * * // 每10秒
```
-### ֧�ֵ��
+### 支持的语法
-#### 1. ͨ��� `*`
+#### 1. 通配符 `*`
-��ʾ���п��ܵ�ֵ��
+表示所有可能的值。
```
-* * * * * * // ÿ��
-0 * * * * * // ÿ���ӵ�0��
-0 0 * * * * // ÿСʱ��0��0��
+* * * * * * // 每秒
+0 * * * * * // 每分钟的0秒
+0 0 * * * * // 每小时的0分0秒
```
-#### 2. ռλ�� `?`
+#### 2. 占位符 `?`
-��ָ��ֵ��ʵ���ϵȼ��� `*`����Ҫ���ڼ��� Quartz ������ Cron ʵ�֡�
+不指定值,实际上等价于 `*`,主要用于兼容 Quartz 等其他 Cron 实现。
```
-0 0 0 ? * 1 // ÿ��һ�賿�����ڲ�ָ����
+0 0 0 ? * 1 // 每周一凌晨(日期不指定)
```
-#### 3. ö�� `a,b,c`
+#### 3. 枚举 `a,b,c`
-�г����ָ��ֵ��
+列出多个指定值。
```
-0 0 0 1,15 * * // ÿ��1�ź�15���賿
-0 0 8,12,18 * * * // ÿ��8�㡢12�㡢18��
+0 0 0 1,15 * * // 每月1号和15号凌晨
+0 0 8,12,18 * * * // 每天8点、12点、18点
```
-#### 4. ��Χ `a-b`
+#### 4. 范围 `a-b`
-��ʾһ��������Χ�������䣩��
+表示一个连续范围(闭区间)。
```
-0 0 2 * * 1-5 // ��һ�������賿2��
-0 0 9-17 * * * // ÿ��9�㵽17�㣨ÿСʱ��
+0 0 2 * * 1-5 // 周一到周五凌晨2点
+0 0 9-17 * * * // 每天9点到17点(每小时)
```
-#### 5. ���� `*/n`��`a/n`��`a-b/n`
+#### 5. 步进 `*/n`、`a/n`、`a-b/n`
-��ʾ����һ��������ѡ��ֵ��
+表示按照一定的增量选择值。
-- `*/n`����0��ʼ��ÿ��nѡһ��
-- `a/n`����a��ʼ��ÿ��nѡһ��
-- `a-b/n`����a��b��Χ�ڣ�ÿ��nѡһ��
+- `*/n`:从0开始,每隔n选一个
+- `a/n`:从a开始,每隔n选一个
+- `a-b/n`:在a到b范围内,每隔n选一个
```
-*/2 * * * * * // ÿ2�루0,2,4,6...�룩
-5/20 * * * * * // ÿ���ӵ�5�롢25�롢45��
-0 */30 * * * * // ÿ30����
-0 0 0 */5 * * // ÿ5��
+*/2 * * * * * // 每2秒(0,2,4,6...秒)
+5/20 * * * * * // 每分钟的5秒、25秒、45秒
+0 */30 * * * * // 每30分钟
+0 0 0 */5 * * // 每5天
```
-#### 6. �ڼ������ڼ� `d#k` �� `d#Lk`
+#### 6. 第几个星期几 `d#k` 和 `d#Lk`
-�������ֶ�֧�֣����ڱ���"ÿ�µڼ������ڼ�"��
+仅星期字段支持,用于表达"每月第几个星期几"。
-- `d#k`��ÿ�µ�k������d
-- `d#Lk`��ÿ�µ�����k������d
+- `d#k`:每月第k个星期d
+- `d#Lk`:每月倒数第k个星期d
```
-0 0 0 ? ? 1#1 // ÿ�µ�1����һ�賿
-0 0 0 ? ? 5#2 // ÿ�µ�2�������賿
-0 0 0 ? ? 1#L1 // ÿ�����1����һ�賿
-0 0 0 ? ? 3-5#L2 // ÿ�µ�����2�������������賿
+0 0 0 ? ? 1#1 // 每月第1个周一凌晨
+0 0 0 ? ? 5#2 // 每月第2个周五凌晨
+0 0 0 ? ? 1#L1 // 每月最后1个周一凌晨
+0 0 0 ? ? 3-5#L2 // 每月倒数第2个周三到周五凌晨
```
-**ע��**��`#` ��Ὣ������ģ 7����˿����� 7 ��ʾ���ա�
+**注意**:`#` 语法会将星期数模 7,因此可以用 7 表示周日。
---
-## ����ƫ��
+## 星期偏移
-### Ĭ����Ϊ
+### 默认行为
-Cron Ĭ�ϲ��� Linux/.NET ���
-- `0` ��ʾ���� (Sunday)
-- `1` ��ʾ��һ (Monday)
-- `2` ��ʾ�ܶ� (Tuesday)
+Cron 默认采用 Linux/.NET 风格:
+- `0` 表示周日 (Sunday)
+- `1` 表示周一 (Monday)
+- `2` 表示周二 (Tuesday)
- ...
-- `6` ��ʾ���� (Saturday)
+- `6` 表示周六 (Saturday)
-### Sunday ����
+### Sunday 属性
-`Sunday` �������ڵ���"����"��Ӧ������ƫ�ƣ�
+`Sunday` 属性用于调整"周日"对应的数字偏移:
```csharp
var cron = new Cron();
-cron.Sunday = 0; // Ĭ��ֵ��0��ʾ����
-// 0=���գ�1=��һ��2=�ܶ�...
+cron.Sunday = 0; // 默认值,0表示周日
+// 0=周日,1=周一,2=周二...
-cron.Sunday = 1; // ��Ϊ1��ʾ����
-// 1=���գ�2=��һ��3=�ܶ�...
+cron.Sunday = 1; // 修改为1表示周日
+// 1=周日,2=周一,3=周二...
```
-**ʹ�ý���**��
-- һ������±���Ĭ�� `Sunday = 0` ����
-- �����Ҫ��������ϵͳ����ijЩ���ݿ⣩���ɵ���Ϊ `Sunday = 1`
-- `Parse` ���������Զ��ƶ� `Sunday`����Ҫ�ֶ�����
+**使用建议**:
+- 一般情况下保持默认 `Sunday = 0` 即可
+- 如果需要兼容其他系统(如某些数据库),可调整为 `Sunday = 1`
+- `Parse` 方法不会自动推断 `Sunday`,需要手动设置
---
-## ���� API
+## 核心 API
-### IsTime - �ж�ʱ���Ƿ�ƥ��
+### IsTime - 判断时间是否匹配
```csharp
-/// <summary>ָ��ʱ���Ƿ�λ�ڱ���ʽ֮��</summary>
-/// <param name="time">Ҫ�жϵ�ʱ��</param>
-/// <returns>�Ƿ�ƥ��</returns>
+/// <summary>指定时间是否位于表达式之内</summary>
+/// <param name="time">要判断的时间</param>
+/// <returns>是否匹配</returns>
public Boolean IsTime(DateTime time)
```
-**ʾ��**��
+**示例**:
```csharp
var cron = new Cron("0 0 2 * * 1-5");
var time = new DateTime(2025, 1, 6, 2, 0, 0);
if (cron.IsTime(time))
{
- Console.WriteLine("ƥ��");
+ Console.WriteLine("匹配");
}
```
-**ע������**��
-- �ж�ʱ�ῼ���롢�֡�ʱ���ա��¡���������ά��
-- �����ֶ�֧��"�ڼ������ڼ�"�ĸ����ж�
-- ʱ��ᰴ�� `Sunday` ���Խ������ڼ���
+**注意事项**:
+- 判断时会考虑秒、分、时、日、月、星期所有维度
+- 星期字段支持"第几个星期几"的复杂判断
+- 时间会按照 `Sunday` 属性进行星期计算
-### GetNext - ��ȡ��һ��ִ��ʱ��
+### GetNext - 获取下一次执行时间
```csharp
-/// <summary>���ָ��ʱ��֮�����һ��ִ��ʱ�䣬����ָ��ʱ��</summary>
-/// <param name="time">�Ӹ�ʱ�������һ���������һ��ִ��ʱ��</param>
-/// <returns>��һ��ִ��ʱ�䣨�뼶�������û��ƥ������Сʱ��</returns>
+/// <summary>获得指定时间之后的下一次执行时间,不含指定时间</summary>
+/// <param name="time">从该时间秒的下一秒算起的下一个执行时间</param>
+/// <returns>下一次执行时间(秒级),如果没有匹配则返回最小时间</returns>
public DateTime GetNext(DateTime time)
```
-**ʾ��**��
+**示例**:
```csharp
-var cron = new Cron("0 0 2 * * *"); // ÿ���賿2��
+var cron = new Cron("0 0 2 * * *"); // 每天凌晨2点
var now = DateTime.Now;
var next = cron.GetNext(now);
-Console.WriteLine($"��һ��ִ�У�{next:yyyy-MM-dd HH:mm:ss}");
+Console.WriteLine($"下一次执行:{next:yyyy-MM-dd HH:mm:ss}");
```
-**ע������**��
-- �������ʱ����к��루�� 09:14:23.456��������ǰ���뵽��һ�루09:14:24�����ټ���
-- ���ص�ʱ�䲻���������ʱ�䱾��
-- ���1�����Ҳ���ƥ��ʱ�䣬���� `DateTime.MinValue`
-- **���ܾ���**���÷���ͨ������������ң�������1�꣬���ʺ�Ƶ������
+**注意事项**:
+- 如果传入时间带有毫秒(如 09:14:23.456),会向前对齐到下一秒(09:14:24)后再计算
+- 返回的时间不包含传入的时间本身
+- 如果1年内找不到匹配时间,返回 `DateTime.MinValue`
+- **性能警告**:该方法通过逐秒遍历查找,最多遍历1年,不适合频繁调用
-### GetPrevious - ��ȡ��һ��ִ��ʱ��
+### GetPrevious - 获取上一次执行时间
```csharp
-/// <summary>�����ָ��ʱ����ϱ���ʽ�������ȥʱ�䣨�뼶��</summary>
-/// <param name="time">��ʱ��</param>
-/// <returns>��һ��ִ��ʱ�䣬���û��ƥ������Сʱ��</returns>
+/// <summary>获得与指定时间符合表达式的最近过去时间(秒级)</summary>
+/// <param name="time">基准时间</param>
+/// <returns>上一次执行时间,如果没有匹配则返回最小时间</returns>
public DateTime GetPrevious(DateTime time)
```
-**ʾ��**��
+**示例**:
```csharp
var cron = new Cron("0 0 2 * * *");
var prev = cron.GetPrevious(DateTime.Now);
-Console.WriteLine($"��һ��ִ�У�{prev:yyyy-MM-dd HH:mm:ss}");
+Console.WriteLine($"上一次执行:{prev:yyyy-MM-dd HH:mm:ss}");
```
-### ���� Cron ����
+### 批量 Cron 计算
```csharp
-/// <summary>��һ��Cron����ʽ����ȡ��һ��ִ��ʱ��</summary>
+/// <summary>对一批Cron表达式,获取下一次执行时间</summary>
public static DateTime GetNext(String[] crons, DateTime time)
-/// <summary>��һ��Cron����ʽ����ȡǰһ��ִ��ʱ��</summary>
+/// <summary>对一批Cron表达式,获取前一次执行时间</summary>
public static DateTime GetPrevious(String[] crons, DateTime time)
```
-**ʾ��**��
+**示例**:
```csharp
-var crons = new[] { "0 0 2 * * *", "0 0 14 * * *" }; // ÿ��2���14��
+var crons = new[] { "0 0 2 * * *", "0 0 14 * * *" }; // 每天2点和14点
var next = Cron.GetNext(crons, DateTime.Now);
-Console.WriteLine($"��һ��ִ�У�{next}");
+Console.WriteLine($"下一次执行:{next}");
```
---
-## ��� TimerX ʹ��
+## 配合 TimerX 使用
-Cron �����ʹ�ó�������� `TimerX` ʵ�ֶ�ʱ����
+Cron 最常见的使用场景是配合 `TimerX` 实现定时任务:
```csharp
using NewLife.Threading;
-// ���� Cron ��ʱ����ÿ������������8��ִ��
+// 创建 Cron 定时器:每个工作日早上8点执行
var timer = new TimerX(state =>
{
- Console.WriteLine($"ִ������{DateTime.Now}");
+ Console.WriteLine($"执行任务:{DateTime.Now}");
}, null, "0 0 8 * * 1-5");
-// ֧�ֶ�� Cron ����ʽ���ֺŷָ�
+// 支持多个 Cron 表达式,分号分隔
var timer2 = new TimerX(state =>
{
- Console.WriteLine("ִ������");
-}, null, "0 0 2 * * 1-5;0 0 3 * * 6"); // ������2�㣬����3��
+ Console.WriteLine("执行任务");
+}, null, "0 0 2 * * 1-5;0 0 3 * * 6"); // 工作日2点,周六3点
-// ʹ����ϼǵ��ͷ�
+// 使用完毕记得释放
timer.Dispose();
timer2.Dispose();
```
-�����[TimerX ʹ���ֲ�](timerx-����ʱ��TimerX.md)
+详见:[TimerX 使用手册](timerx-高级定时器TimerX.md)
---
-## ���ñ���ʽʾ��
+## 常用表达式示例
-### ÿ��/ÿ��/ÿʱ
+### 每秒/每分/每时
```
-* * * * * * // ÿ��
-*/2 * * * * * // ÿ2��
-*/5 * * * * * // ÿ5��
-0 * * * * * // ÿ����
-0 */5 * * * * // ÿ5����
-0 */15 * * * * // ÿ15����
-0 */30 * * * * // ÿ30����
-0 0 * * * * // ÿСʱ
-0 0 */2 * * * // ÿ2Сʱ
+* * * * * * // 每秒
+*/2 * * * * * // 每2秒
+*/5 * * * * * // 每5秒
+0 * * * * * // 每分钟
+0 */5 * * * * // 每5分钟
+0 */15 * * * * // 每15分钟
+0 */30 * * * * // 每30分钟
+0 0 * * * * // 每小时
+0 0 */2 * * * // 每2小时
```
-### ÿ��̶�ʱ��
+### 每天固定时间
```
-0 0 0 * * * // ÿ���賿0��
-0 0 1 * * * // ÿ���賿1��
-0 30 8 * * * // ÿ��8��30��
-0 0 12 * * * // ÿ������12��
-0 0 23 * * * // ÿ������23��
-0 0 0,12 * * * // ÿ��0���12��
-0 0 8,12,18 * * * // ÿ��8�㡢12�㡢18��
+0 0 0 * * * // 每天凌晨0点
+0 0 1 * * * // 每天凌晨1点
+0 30 8 * * * // 每天8点30分
+0 0 12 * * * // 每天中午12点
+0 0 23 * * * // 每天晚上23点
+0 0 0,12 * * * // 每天0点和12点
+0 0 8,12,18 * * * // 每天8点、12点、18点
```
-### ������/��ĩ
+### 工作日/周末
```
-0 0 9 * * 1-5 // ÿ������������9��
-0 0 2 * * 1-5 // ÿ���������賿2��
-0 0 10 * * 6,0 // ÿ����ĩ�����������գ�10��
-0 0 0 * * 1 // ÿ��һ�賿
-0 0 0 * * 5 // ÿ�����賿
+0 0 9 * * 1-5 // 每个工作日早上9点
+0 0 2 * * 1-5 // 每个工作日凌晨2点
+0 0 10 * * 6,0 // 每个周末(周六、周日)10点
+0 0 0 * * 1 // 每周一凌晨
+0 0 0 * * 5 // 每周五凌晨
```
-### ÿ�¹̶�����
+### 每月固定日期
```
-0 0 0 1 * * // ÿ��1���賿
-0 0 0 15 * * // ÿ��15���賿
-0 0 0 1,15 * * // ÿ��1�ź�15���賿
-0 0 0 L * * // ÿ�����һ���賿��������������
+0 0 0 1 * * // 每月1号凌晨
+0 0 0 15 * * // 每月15号凌晨
+0 0 0 1,15 * * // 每月1号和15号凌晨
+0 0 0 L * * // 每月最后一天凌晨(需配合特殊处理)
```
-### ���ӳ���
+### 复杂场景
```
-0 0 2 * * 1-5 // ÿ���������賿2��
-5/20 * * * * * // ÿ���ӵ�5�롢25�롢45��
-0 0 0 ? ? 1#1 // ÿ�µ�1����һ�賿
-0 0 0 ? ? 5#L1 // ÿ�����1�������賿
-0 0 0 1-7 * 1 // ÿ�µ�һ����һ�賿����һ��д����
+0 0 2 * * 1-5 // 每个工作日凌晨2点
+5/20 * * * * * // 每分钟的5秒、25秒、45秒
+0 0 0 ? ? 1#1 // 每月第1个周一凌晨
+0 0 0 ? ? 5#L1 // 每月最后1个周五凌晨
+0 0 0 1-7 * 1 // 每月第一个周一凌晨(另一种写法)
```
---
-## ע������������
+## 注意事项与限制
-### ���ܿ���
+### 性能考量
-`GetNext` �� `GetPrevious` ����ͨ��**�������**ʵ�֣������ص㣺
-- **�ʺϳ���**����Ƶ�ʵ��ã��綨ʱ�����ʼ��ʱ������һ��ִ��ʱ��
-- **���ʺϳ���**����Ƶ���á�ʵʱ·�����ȵ����
-- **��������**��������1�꣨Լ3ǧ���ѭ����
+`GetNext` 和 `GetPrevious` 方法通过**逐秒遍历**实现,性能特点:
+- **适合场景**:低频率调用,如定时任务初始化时计算下一次执行时间
+- **不适合场景**:高频调用、实时路径、热点代码
+- **性能上限**:最多遍历1年(约3千万次循环)
-**����**��
-- �� `TimerX` ��ʼ��ʱ����һ����һ��ִ��ʱ�伴��
-- ������ѭ����Ƶ������
-- ��������ܳ�������������ʵ���㷨
+**建议**:
+- 在 `TimerX` 初始化时计算一次下一次执行时间即可
+- 避免在循环中频繁调用
+- 如需高性能场景,考虑自行实现算法
-### ��֧������ֶ�
+### 不支持年份字段
-��ǰʵ�ֽ�֧��6���ֶΣ��롢�֡�ʱ���ա��¡����ڣ���**��֧�ֵ�7���ֶ�"��"**��
+当前实现仅支持6个字段(秒、分、时、日、月、星期),**不支持第7个字段"年"**。
-### �ֶ�ȱʡ����
+### 字段缺省规则
-- �������ʽ����6���ֶΣ�ȱʡ�ֶ�Ĭ��Ϊ `*`
-- ���磺`0 0 2 * *` �ᱻ����Ϊ `0 0 2 * * *`
+- 如果表达式少于6个字段,缺省字段默认为 `*`
+- 例如:`0 0 2 * *` 会被解析为 `0 0 2 * * *`
-### �����ֶ�������
+### 星期字段特殊性
-- ���ڼ����� `Sunday` ����Ӱ��
-- `#` ��Ὣ������ģ7����� 7 Ҳ���Ա�ʾ����
-- ���ڷ�Χ�� 0-6������� `Sunday` ����Ϊ 1-7��
+- 星期计算受 `Sunday` 属性影响
+- `#` 语法会将星期数模7,因此 7 也可以表示周日
+- 星期范围是 0-6(或根据 `Sunday` 调整为 1-7)
---
-## Դ�����
+## 源码解析
-### ��������
+### 解析流程
```csharp
public Boolean Parse(String expression)
{
var ss = expression.Split([' '], StringSplitOptions.RemoveEmptyEntries);
- // ������
+ // 解析秒
if (!TryParse(ss[0], 0, 60, out var vs)) return false;
Seconds = vs;
- // ������
+ // 解析分
if (!TryParse(ss.Length > 1 ? ss[1] : "*", 0, 60, out vs)) return false;
Minutes = vs;
- // ... ���ν���ʱ���ա���
+ // ... 依次解析时、日、月
- // �������ڣ��������
+ // 解析星期(特殊处理)
var weeks = new Dictionary<Int32, Int32>();
if (!TryParseWeek(ss.Length > 5 ? ss[5] : "*", 0, 7, weeks)) return false;
DaysOfWeek = weeks;
@@ -418,12 +418,12 @@ public Boolean Parse(String expression)
}
```
-### ƥ���ж�
+### 匹配判断
```csharp
public Boolean IsTime(DateTime time)
{
- // ����ʱ���ж�
+ // 基础时间判断
if (!Seconds.Contains(time.Second) ||
!Minutes.Contains(time.Minute) ||
!Hours.Contains(time.Hour) ||
@@ -431,12 +431,12 @@ public Boolean IsTime(DateTime time)
!Months.Contains(time.Month))
return false;
- // �����жϣ����� Sunday ƫ�ƣ�
+ // 星期判断(考虑 Sunday 偏移)
var w = (Int32)time.DayOfWeek + Sunday;
if (!DaysOfWeek.TryGetValue(w, out var index)) return false;
- // �ڼ������ڼ��жϣ�index > 0 ��ʾ�����ڼ�����< 0 ��ʾ������
- // ... ������
+ // 第几个星期几判断(index > 0 表示正数第几个,< 0 表示倒数)
+ // ... 复杂逻辑
return true;
}
@@ -444,60 +444,60 @@ public Boolean IsTime(DateTime time)
---
-## ��������
+## 常见问题
-### 1. ����ʽ����ʧ�ܣ�
+### 1. 表达式解析失败?
-�����Ƿ���ȷ��
-- �ֶ������Ƿ�Ϊ6��������٣�ȱʡĬ��`*`��
-- ��Χֵ�Ƿ�����Ч��Χ��
-- ����ֵ��Ƿ���ȷ
+检查语法是否正确:
+- 字段数量是否为6个(或更少,缺省默认`*`)
+- 范围值是否在有效范围内
+- 步进值语法是否正确
```csharp
var cron = new Cron();
if (!cron.Parse("0 0 2 * * 1-5"))
{
- Console.WriteLine("����ʧ��");
+ Console.WriteLine("解析失败");
}
```
-### 2. GetNext ���� MinValue��
+### 2. GetNext 返回 MinValue?
-˵��1�����Ҳ���ƥ���ʱ�䣬����ԭ��
-- ����ʽ����ì�ܣ��� `0 0 0 31 2 *` 2��û��31�ţ�
-- ���ں����ڳ�ͻ
+说明1年内找不到匹配的时间,可能原因:
+- 表达式本身矛盾(如 `0 0 0 31 2 *` 2月没有31号)
+- 日期和星期冲突
-### 3. ���ڼ��㲻�ԣ�
+### 3. 星期计算不对?
-��� `Sunday` �������ã�
+检查 `Sunday` 属性设置:
```csharp
var cron = new Cron("0 0 0 * * 1");
-cron.Sunday = 0; // ȷ��ƫ����
+cron.Sunday = 0; // 确认偏移量
```
-### 4. ����Ӱ����㣿
+### 4. 毫秒影响计算?
-`GetNext` ���Զ��������룬���϶��뵽��һ�룺
+`GetNext` 会自动处理毫秒,向上对齐到下一秒:
```csharp
-var time = new DateTime(2025, 1, 1, 9, 14, 23, 456); // ������
-var next = cron.GetNext(time); // �� 09:14:24 ��ʼ����
+var time = new DateTime(2025, 1, 1, 9, 14, 23, 456); // 带毫秒
+var next = cron.GetNext(time); // 从 09:14:24 开始计算
```
---
-## �����
+## 参考资料
-- **TimerX �ĵ�**: [timerx-����ʱ��TimerX.md](timerx-����ʱ��TimerX.md)
-- **������Cron�ο�**: https://help.aliyun.com/document_detail/64769.html
-- **�����ĵ�**: https://newlifex.com/core/cron
-- **Դ��**: https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/Cron.cs
+- **TimerX 文档**: [timerx-高级定时器TimerX.md](timerx-高级定时器TimerX.md)
+- **阿里云Cron参考**: https://help.aliyun.com/document_detail/64769.html
+- **在线文档**: https://newlifex.com/core/cron
+- **源码**: https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/Cron.cs
---
-## ������־
+## 更新日志
-- **2025-01**: �����ĵ���������ϸʾ����Դ�����
-- **2024**: ֧�� .NET 9.0
-- **2023**: ����������
-- **2022**: ��������Cron���㷽��
-- **2020**: ��ʼ�汾��֧�ֻ���Cron�
+- **2025-01**: 完善文档,补充详细示例和源码解析
+- **2024**: 支持 .NET 9.0
+- **2023**: 优化解析性能
+- **2022**: 增加批量Cron计算方法
+- **2020**: 初始版本,支持基本Cron语法
diff --git "a/Doc/CSV\346\225\260\346\215\256\345\272\223CsvDb.md" "b/Doc/CSV\346\225\260\346\215\256\345\272\223CsvDb.md"
index e4e6262..ec9f2dc 100644
--- "a/Doc/CSV\346\225\260\346\215\256\345\272\223CsvDb.md"
+++ "b/Doc/CSV\346\225\260\346\215\256\345\272\223CsvDb.md"
@@ -1,223 +1,223 @@
-# CsvDb ʹ���ֲ�
+# CsvDb 使用手册
-���ĵ�����Դ�� `NewLife.Core/IO/CsvDb.cs` �������� `NewLife.Core/IO/CsvFile.cs`������˵�� `CsvDb<T>`��CSV �ļ����������ݿ⣩�����Ŀ�ꡢ���ݸ�ʽ������ģ���� CRUD �÷���
+本文档基于源码 `NewLife.Core/IO/CsvDb.cs` 与其依赖 `NewLife.Core/IO/CsvFile.cs`,用于说明 `CsvDb<T>`(CSV 文件轻量级数据库)的设计目标、数据格式、事务模型与 CRUD 用法。
-> �ؼ��ʣ���д��������˳���ѯ���������С���ͷӳ�䡢���桢���仺�桢���л���������
+> 关键词:追加写、高性能顺序查询、跳过损坏行、表头映射、事务缓存、反射缓存、序列化属性名。
---
-## 1. ����
+## 1. 概述
-`CsvDb<T>` ��һ���� CSV �ļ���Ϊ�־û��洢�ġ����������ݿ⡱���ʺϣ�
+`CsvDb<T>` 是一个以 CSV 文件作为持久化存储的“轻量级数据库”,适合:
-- ����������Ҫ **�����ӣ�Append��**��
-- ��Ҫ **˳��ɨ��ʽ���ٲ�ѯ**��`Query`����
-- ������/ɾ������/ɾ�������ǡ�ȫ����д������
-- ����˳�����SQLite �ȹ�ϵ�������Ƿ��ػ�������`CsvDb<T>` ��ȡʱ�� **��������**����߿ɻָ��ԡ�
+- 大量数据需要 **快速追加(Append)**;
+- 需要 **顺序扫描式快速查询**(`Query`);
+- 很少修改/删除(修改/删除本质是“全量重写”);
+- 桌面端场景,SQLite 等关系库可能因非法关机导致损坏;`CsvDb<T>` 读取时可 **跳过损坏行**,提高可恢复性。
-��ҪԼ����
+重要约束:
-- **��֧���̰߳�ȫ**����ע����ȷҪ�����ȷ�����̲߳�������Դ���в��ַ���ʹ�� `lock (this)` ������������������������ơ�
+- **不支持线程安全**:类注释明确要求“务必确保单线程操作”。源码中部分方法使用 `lock (this)` 防并发,但并非完整并发设计。
---
-## 2. �����ļ���ʽ
+## 2. 数据文件格式
-### 2.1 �ļ�ͷ��Header��
+### 2.1 文件头(Header)
-��������������Դ��ʵ�� `T` �Ĺ���ʵ�����ԣ�
+首行是列名,来源于实体 `T` 的公共实例属性:
-- ͨ�����仺�� `_properties = typeof(T).GetProperties(...)` ��ȡ���ԣ�
-- ����ʹ�� `SerialHelper.GetName(PropertyInfo)`�������������������Ա��������л���/����һ�¡�
+- 通过反射缓存 `_properties = typeof(T).GetProperties(...)` 获取属性;
+- 列名使用 `SerialHelper.GetName(PropertyInfo)`(而不是属性名),以保持与序列化名/特性一致。
-д�ļ�ʱ��
+写文件时:
-- ���ļ�Ϊ�գ�`FileStream.Position == 0`��ʱд���ͷ��
+- 当文件为空(`FileStream.Position == 0`)时写入表头。
-��ȡ�ļ�ʱ��
+读取文件时:
-- ������Ϊ CSV ������
-- �������ļ��� -> ������������ӳ������ `columnToProperty`������ÿ�ж����ֵ䡣
+- 首行作为 CSV 列名;
+- 建立“文件列 -> 属性索引”的映射数组 `columnToProperty`,避免每行都查字典。
-### 2.2 ������Data Rows��
+### 2.2 数据行(Data Rows)
-ÿ�ж�Ӧһ�� `T` ʵ����
+每行对应一个 `T` 实例。
-д��ʱ��
+写入时:
-- �� `T` ʵ�� `IModel`���������� `src[e.Name]` ��ȡֵ��
-- ����ͨ������ `item.GetValue(e)` ��ȡ����ֵ��
+- 若 `T` 实现 `IModel`:按属性名 `src[e.Name]` 读取值;
+- 否则通过反射 `item.GetValue(e)` 读取属性值。
-��ȡʱ��
+读取时:
-- ���� `new T()`��
-- ��ÿ�г���Ŀ����������������У�飨����/����/���ڵȣ���У��ʧ�����������ֶΣ�
-- ���ַ��� `raw` ת��ΪĿ�����ͣ�`raw.ChangeType(pi.PropertyType)`��
-- ��ͨ�� `IModel` �� `model.SetValue(pi, value)` ��ֵ��
+- 创建 `new T()`;
+- 对每列尝试按目标属性类型做基础校验(整数/浮点/日期等),校验失败则跳过该字段;
+- 将字符串 `raw` 转换为目标类型:`raw.ChangeType(pi.PropertyType)`;
+- 再通过 `IModel` 或 `model.SetValue(pi, value)` 赋值。
---
-## 3. ��������
+## 3. 核心属性
### 3.1 `FileName`
-- ���ͣ�`String?`
-- ���壺CSV �����ļ�·��
+- 类型:`String?`
+- 语义:CSV 数据文件路径
-ʹ��Ҫ��
+使用要求:
-- �������ã�δ���õ��û��׳� `ArgumentNullException`���� `GetFile()`����
+- 必须设置;未设置调用会抛出 `ArgumentNullException`(见 `GetFile()`)。
### 3.2 `Encoding`
-- ���ͣ�`Encoding`
-- Ĭ�ϣ�`Encoding.UTF8`
+- 类型:`Encoding`
+- 默认:`Encoding.UTF8`
-Ӱ�죺
+影响:
-- ��ȡ��д�� CSV ʱ���ݸ� `CsvFile.Encoding`��
+- 读取与写入 CSV 时传递给 `CsvFile.Encoding`。
### 3.3 `Comparer`
-- ���ͣ�`IEqualityComparer<T>`
-- Ĭ�ϣ�`EqualityComparer<T>.Default`
+- 类型:`IEqualityComparer<T>`
+- 默认:`EqualityComparer<T>.Default`
-��;��
+用途:
-- `Remove(T)` / `Remove(IEnumerable<T>)` / `Find(T)` / `Set(T, ...)` �������жϡ�ʵ���Ƿ���ͬ����
+- `Remove(T)` / `Remove(IEnumerable<T>)` / `Find(T)` / `Set(T, ...)` 用它来判断“实体是否相同”。
-��ͨ�����캯�� `CsvDb(Func<T?, T?, Boolean> comparer)` �����Զ���Ƚ�����
+可通过构造函数 `CsvDb(Func<T?, T?, Boolean> comparer)` 传入自定义比较逻辑。
---
-## 4. ����ģ�ͣ�����д��
+## 4. 事务模型(缓存写)
### 4.1 `BeginTransaction()`
-- ��Ϊ���ѵ�ǰ�ļ�ȫ�����ݶ����ڴ棨`_cache = FindAll().ToList()`����
-- ֮��� `Add/Remove/Set/Clear/Find/Query` �����ڻ������������Ƶ�� I/O����
+- 行为:把当前文件全部数据读入内存(`_cache = FindAll().ToList()`)。
+- 之后的 `Add/Remove/Set/Clear/Find/Query` 将基于缓存操作(避免频繁 I/O)。
### 4.2 `Commit()`
-- ��Ϊ���� `_cache` ����д���ļ���`Write(_cache, false)`����Ȼ����ջ��档
+- 行为:把 `_cache` 覆盖写回文件(`Write(_cache, false)`),然后清空缓存。
### 4.3 `Rollback()`
-- ��Ϊ������ջ��棬��д�ش��̡�
+- 行为:仅清空缓存,不写回磁盘。
-### 4.4 Dispose �Զ��ύ
+### 4.4 Dispose 自动提交
-`CsvDb<T>` �̳� `DisposeBase`���� `Dispose(Boolean)` �����л���� `Commit()`��
+`CsvDb<T>` 继承 `DisposeBase`,其 `Dispose(Boolean)` 覆盖中会调用 `Commit()`:
-- �����������������л��棬�ͷŶ���ʱ���Զ��ύ��������ʷ������Ϊ����
+- 若开启过事务且仍有缓存,释放对象时会自动提交(保持历史兼容行为)。
-���飺
+建议:
-- �ԡ���������Ϊ���ij�����������ʾ���� `Commit()`�������쳣ʱ���ύ��
+- 对“批处理”为主的场景,建议显示调用 `Commit()`,避免异常时误提交。
---
-## 5. �/��
+## 5. 写入/追加
### 5.1 `Write(IEnumerable<T> models, Boolean append)`
-���壺����д�롣
+语义:批量写入。
-�ؼ��㣺
+关键点:
-- ���ļ���ʽ��`FileMode.OpenOrCreate` + `FileAccess.ReadWrite` + `FileShare.ReadWrite`��
-- `append=true` ʱ�ƶ����ļ�β��`fs.Position = fs.Length`��
-- �ļ�Ϊ��ʱд���ͷ��
-- д���ִ�� `fs.SetLength(fs.Position)`��
- - ����д��`append=false`���������ض�ԭ�ļ����ಿ�֣�
- - ��дʱҲ��ѳ�������Ϊ��ǰλ�ã�ͨ���ȼۣ���
+- 打开文件方式:`FileMode.OpenOrCreate` + `FileAccess.ReadWrite` + `FileShare.ReadWrite`;
+- `append=true` 时移动到文件尾:`fs.Position = fs.Length`;
+- 文件为空时写入表头;
+- 写完后执行 `fs.SetLength(fs.Position)`:
+ - 覆盖写(`append=false`)场景:截断原文件多余部分;
+ - 追加写时也会把长度设置为当前位置(通常等价)。
### 5.2 `Add(T model)` / `Add(IEnumerable<T> models)`
-- ���� `BeginTransaction()`�����ӵ� `_cache`��
-- ����ֱ�� `Write(..., append:true)`��������á�
+- 若已 `BeginTransaction()`:仅追加到 `_cache`;
+- 否则:直接 `Write(..., append:true)`,性能最好。
---
-## 6. ��ѯ
+## 6. 查询
### 6.1 `IEnumerable<T> Query(Func<T, Boolean>? predicate, Int32 count = -1)`
-���壺˳��ɨ���ѯ�����践�ء�
+语义:顺序扫描查询,按需返回。
-��ΪҪ�㣺
+行为要点:
-- ��������`_cache!=null`��ʱ���ӻ���ö�٣������� `yield return`��
-- δ��������ʱ��
- - ʹ�� `CsvFile.ReadLine()` ���¼��ȡ��
- - ������¼��Ϊ��ͷ��
- - ����ÿ����¼����ӳ����䵽�¶���
+- 开启事务(`_cache!=null`)时:从缓存枚举,命中则 `yield return`;
+- 未开启事务时:
+ - 使用 `CsvFile.ReadLine()` 逐记录读取;
+ - 首条记录作为表头;
+ - 后续每条记录根据映射填充到新对象。
-�������
+损坏行处理:
-- ����ת���������κ��쳣�ᱻ����¼��`XTrace.WriteException(ex)`��������������
-- ��һ����û���κ��ֶγɹ�ƥ�䣨`success == 0`������Ϊ���в�������
+- 类型转换过程中任何异常会被捕获并记录(`XTrace.WriteException(ex)`),该行跳过;
+- 若一行中没有任何字段成功匹配(`success == 0`),视为损坏行并跳过。
-`count`��
+`count`:
-- Ĭ�� `-1` ��ʾ�����ƣ�
-- ÿ `yield` һ�κ� `--count`���� 0 ������
+- 默认 `-1` 表示不限制;
+- 每 `yield` 一次后 `--count`,到 0 结束。
### 6.2 `T? Find(Func<T, Boolean>? predicate)`
-- �ȼ��� `Query(predicate, 1).FirstOrDefault()`��
+- 等价于 `Query(predicate, 1).FirstOrDefault()`。
### 6.3 `IList<T> FindAll()`
-- ��������ʱ���ػ��渱�� `_cache.ToList()`��
-- �����ȡȫ����
+- 开启事务时返回缓存副本 `_cache.ToList()`;
+- 否则读取全部。
### 6.4 `Int32 FindCount()`
-- ��������ʹ�� `StreamReader.ReadLine()` ���м���������ͷ������
-- ע�⣺���ﰴ�����м����������� CSV �����ֶ��ڻ��е�������ڳ�������� CSV ��ͨ���ɽ��ܡ�
+- 非事务场景:使用 `StreamReader.ReadLine()` 逐行计数(跳过头部)。
+- 注意:这里按物理行计数,不考虑 CSV 引号字段内换行的情况;在常规表格型 CSV 中通常可接受。
---
-## 7. ������ɾ����ȫ����д��������
+## 7. 更新与删除(全量重写,较慢)
### 7.1 `Remove(Func<T, Boolean> predicate)`
-- ���������� `_cache` ִ�� `RemoveAll`��
-- ����
- - `FindAll()` ����ȫ����
- - ���˵������
- - �� `Write(list, false)` ����д�ء�
+- 若开启事务:对 `_cache` 执行 `RemoveAll`;
+- 否则:
+ - `FindAll()` 读入全部;
+ - 过滤掉命中项;
+ - 再 `Write(list, false)` 覆盖写回。
### 7.2 `Update(T model)` / `Set(T model)`
-- `Update`��ֻ���£��������� `false`��
-- `Set`����������£�����������һ����
+- `Update`:只更新,不存在则返回 `false`;
+- `Set`:存在则更新,不存在则追加一条。
-δ��������ʱ��
+未开启事务时:
-- ��ȡȫ�����ڴ棬�ĺ�д�ء�
+- 读取全部到内存,修改后覆盖写回。
---
-## 8. �첽��ѯ��net5+ / netstandard2.1+��
+## 8. 异步查询(net5+ / netstandard2.1+)
-�� `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` ���ṩ��
+在 `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` 下提供:
- `IAsyncEnumerable<T> QueryAsync(Func<T, Boolean>? predicate, Int32 count = -1)`
- `Task<IList<T>> FindAllAsync()`
-ʵ��Ҫ�㣺
+实现要点:
-- �ڲ�ʹ�� `CsvFile.ReadAllAsync()`��
-- ͷ��ӳ������ͬ����һ�£�
-- �����쳣ʱͬ����¼�������С�
+- 内部使用 `CsvFile.ReadAllAsync()`;
+- 头部映射逻辑与同步版一致;
+- 发生异常时同样记录并跳过行。
---
-## 9. ��Сʾ��
+## 9. 最小示例
-### 9.1 ����ʵ��
+### 9.1 定义实体
```csharp
public class User
@@ -228,7 +228,7 @@ public class User
}
```
-### 9.2 ���
+### 9.2 追加写入
```csharp
using NewLife.IO;
@@ -243,7 +243,7 @@ db.Add(new User { Id = 1, Name = "Stone", CreateTime = DateTime.Now });
db.Add(new User { Id = 2, Name = "NewLife", CreateTime = DateTime.Now });
```
-### 9.3 ��ѯ
+### 9.3 查询
```csharp
foreach (var u in db.Query(e => e.Id > 0))
@@ -252,7 +252,7 @@ foreach (var u in db.Query(e => e.Id > 0))
}
```
-### 9.4 ����������
+### 9.4 批处理事务
```csharp
using var db = new CsvDb<User> { FileName = "./user.csv" };
@@ -267,17 +267,17 @@ db.Commit();
---
-## 10. ע�����������ʵ��
+## 10. 注意事项与最佳实践
-1. **��Ƶд�������� `Add`��������**��������д·��������ȫ����д��
-2. **��/ɾ����һ�֡�������������**������ `BeginTransaction()` ���д������� `Commit()`��
-3. **���߳�ʹ��**����ʹ�ڲ��� `lock (this)`��Ҳ��������̲߳�������ͬһ��ʵ����
-4. **��ͷ������������**��д��ʹ�� `SerialHelper.GetName`����ȡ�ǰ�����ӳ�䵽���ԣ������Զ������������л����ԣ���Ҫȷ��д��/��ȡһ�¡�
+1. **高频写入优先用 `Add`(非事务)**:它走追加写路径,避免全量重写。
+2. **修改/删除是一种“批处理操作”**:建议 `BeginTransaction()` 后集中处理,再 `Commit()`。
+3. **单线程使用**:即使内部有 `lock (this)`,也不建议多线程并发操作同一个实例。
+4. **表头列名与属性名**:写入使用 `SerialHelper.GetName`,读取是按列名映射到属性;若你自定义列名(序列化特性),要确保写入/读取一致。
---
-## 11. �������
+## 11. 相关链接
-- �����ĵ���`https://newlifex.com/core/csv_db`
-- Դ�룺`NewLife.Core/IO/CsvDb.cs`
-- ������`NewLife.Core/IO/CsvFile.cs`
+- 在线文档:`https://newlifex.com/core/csv_db`
+- 源码:`NewLife.Core/IO/CsvDb.cs`
+- 依赖:`NewLife.Core/IO/CsvFile.cs`
diff --git "a/Doc/CSV\346\226\207\344\273\266CsvFile.md" "b/Doc/CSV\346\226\207\344\273\266CsvFile.md"
index 1c83e21..efd7723 100644
--- "a/Doc/CSV\346\226\207\344\273\266CsvFile.md"
+++ "b/Doc/CSV\346\226\207\344\273\266CsvFile.md"
@@ -1,146 +1,146 @@
-# CsvFile ʹ���ֲ�
+# CsvFile 使用手册
-���ĵ�����Դ�� `NewLife.Core/IO/CsvFile.cs`������˵�� `CsvFile`��CSV ��д���������Ŀ�ꡢRFC4180 ������Ϊ��ͬ��/�첽 API���Լ����ļ������µ�ʹ�ý��顣
+本文档基于源码 `NewLife.Core/IO/CsvFile.cs`,用于说明 `CsvFile`(CSV 读写器)的设计目标、RFC4180 兼容行为、同步/异步 API,以及大文件场景下的使用建议。
-> �ؼ��ʣ�RFC4180����ʽ�����������ֶΡ�CRLF��������д��Encoding��Separator��
+> 关键词:RFC4180、流式解析、引号字段、CRLF、增量读写、Encoding、Separator。
---
-## 1. ����
+## 1. 概述
-`CsvFile` ��һ�������� CSV �ļ��������������֧࣬�֣�
+`CsvFile` 是一个面向“超大 CSV 文件”的轻量工具类,支持:
-- **���У�Record����ȡ**������¼���������Ǽ� `ReadLine()+Split`��
-- **����д��**��������д�룬����һ���Թ��������ļ���
-- **RFC4180 �����������**��
- - �ֶ�ʹ�� `Separator` �ָ���
- - �ֶ��к��ָ���/����/˫����ʱʹ��˫���Ű�����
- - �ֶ���˫������ `""` ת�壻
- - ���������ֶ��ڲ����ֻ��У������ֶΣ���
+- **逐行(Record)读取**:按记录解析而不是简单 `ReadLine()+Split`;
+- **逐行写入**:按需追加写入,避免一次性构建整个文件;
+- **RFC4180 基本规则兼容**:
+ - 字段使用 `Separator` 分隔;
+ - 字段中含分隔符/换行/双引号时使用双引号包裹;
+ - 字段内双引号用 `""` 转义;
+ - 允许引号字段内部出现换行(跨行字段)。
-������
+适用场景:
-- ���ݵ��뵼����
-- ��Ҫ�Գ��� CSV ����ʽ��ȡ���߶��ߴ�����
-- ��Ҫ��ȷ����������/����/���ŵ��ֶΡ�
+- 数据导入导出;
+- 需要对超大 CSV 做流式读取、边读边处理;
+- 需要正确处理含逗号/换行/引号的字段。
---
-## 2. ��������
+## 2. 核心属性
### 2.1 `Encoding`
-- ���ͣ�`Encoding`
-- Ĭ�ϣ�`Encoding.UTF8`
+- 类型:`Encoding`
+- 默认:`Encoding.UTF8`
-Ӱ�죺
+影响:
-- ��ȡʱ���ڹ��� `StreamReader`��
-- д��ʱ���ڹ��� `StreamWriter`��
+- 读取时用于构造 `StreamReader`;
+- 写入时用于构造 `StreamWriter`。
-˵����
+说明:
-- `EnsureReader()` ʹ�� `new StreamReader(_stream, Encoding)`��Ĭ������ BOM ��⣨`detectEncodingFromByteOrderMarks=true` ΪĬ����Ϊ����
+- `EnsureReader()` 使用 `new StreamReader(_stream, Encoding)`,默认启用 BOM 检测(`detectEncodingFromByteOrderMarks=true` 为默认行为)。
### 2.2 `Separator`
-- ���ͣ�`Char`
-- Ĭ�ϣ�`,`
+- 类型:`Char`
+- 默认:`,`
-˵����
+说明:
-- ��ȡʱ�����ֶηָ���
-- д��ʱ����ƴ���ֶΣ����ݴ��ж��Ƿ���Ҫ�����š�
+- 读取时用于字段分隔;
+- 写入时用于拼接字段,并据此判断是否需要加引号。
---
-## 3. ��������Դ����
+## 3. 构造与资源管理
-### 3.1 ���췽ʽ
+### 3.1 构造方式
- `CsvFile(Stream stream)`
- `CsvFile(Stream stream, Boolean leaveOpen)`
- `CsvFile(String file, Boolean write = false)`
-`write=false`���� `FileAccess.Read` ��ֻ������
+`write=false`:以 `FileAccess.Read` 打开(只读)。
-`write=true`���� `FileAccess.ReadWrite` ����д�����Զ��ضϣ����ʺ������ӻ�д������дʱ�ɵ��÷����� `Position/SetLength`����
+`write=true`:以 `FileAccess.ReadWrite` 打开(读写,不自动截断)。适合增量追加或覆盖写(覆盖写时由调用方控制 `Position/SetLength`)。
### 3.2 `leaveOpen`
-��ʹ�� `CsvFile(Stream, leaveOpen:true)`��
+当使用 `CsvFile(Stream, leaveOpen:true)`:
-- `Dispose()` ����ر� `_stream`��
-- ���Ի� `Flush()`/�ͷ��ڲ� `_reader/_writer`��
+- `Dispose()` 不会关闭 `_stream`;
+- 但仍会 `Flush()`/释放内部 `_reader/_writer`。
-### 3.3 Dispose ��Ϊ
+### 3.3 Dispose 行为
-- `Dispose()` ���� `_writer?.Flush()`������д��������δ���̣�
-- �� `_leaveOpen=false`�����ͷ� `_reader/_writer` ���ر�����
+- `Dispose()` 会先 `_writer?.Flush()`,避免写入器缓冲未落盘;
+- 若 `_leaveOpen=false`:会释放 `_reader/_writer` 并关闭流。
-�� `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` �»��ṩ `DisposeAsync()`��
+在 `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` 下还提供 `DisposeAsync()`。
---
-## 4. ��ȡ��RFC4180 ��� Record ������
+## 4. 读取(RFC4180 风格 Record 解析)
### 4.1 `String[]? ReadLine()`
-��ȡһ����¼��Record���������ֶ����飺
+读取一条记录(Record),返回字段数组:
-- EOF ���� `null`��
-- ֧�������ֶ��ڲ����� `Separator`��`\r\n`��`\n`��
-- `""` ����Ϊ `"`��
-- ֧��β�����ֶΣ����� `a,b,` => �����ֶΣ����һ��Ϊ���ַ�������
+- EOF 返回 `null`;
+- 支持引号字段内部包含 `Separator`、`\r\n`、`\n`;
+- `""` 解析为 `"`;
+- 支持尾部空字段(例如 `a,b,` => 三个字段,最后一个为空字符串)。
### 4.2 `IEnumerable<String[]> ReadAll()`
-ͬ��ö�ٶ�ȡȫ����¼��
+同步枚举读取全部记录:
-- �ڲ�ѭ������ `ReadLine()` ֱ�� EOF��
+- 内部循环调用 `ReadLine()` 直到 EOF。
-### 4.3 �첽��ȡ
+### 4.3 异步读取
-���� `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` �¿��ã�
+仅在 `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` 下可用:
- `ValueTask<String[]?> ReadLineAsync()`
- `IAsyncEnumerable<String[]> ReadAllAsync()`
-�첽ʵ�ֲ����ڲ��ַ���������`Char[4096]`��������
+异步实现采用内部字符缓冲区(`Char[4096]`)解析。
---
-## 5. д�루RFC4180 ���ת�壩
+## 5. 写入(RFC4180 风格转义)
### 5.1 `void WriteLine(IEnumerable<Object?> line)`
-дһ�м�¼���Զ�����β���У���
+写一行记录(自动追加行尾换行):
-- `DateTime`��ʹ�� `ToFullString("")`��
-- `Boolean`��д `1/0`��
-- �������ͣ�`item + ""` ת�ַ�����
-- **�������ַ��������� > 9 �ҿɽ���Ϊ Int64��**��ǰ�� `\t`�����ڱ��� Excel/WPS ����ʾΪ��ѧ��������
-- ���ֶΰ������ָ���/CR/LF/˫���ţ��������˫���ţ������ڲ�˫�����滻Ϊ `""`��
+- `DateTime`:使用 `ToFullString("")`;
+- `Boolean`:写 `1/0`;
+- 其它类型:`item + ""` 转字符串;
+- **长整数字符串(长度 > 9 且可解析为 Int64)**:前置 `\t`,用于避免 Excel/WPS 等显示为科学计数法;
+- 若字段包含:分隔符/CR/LF/双引号,则整体加双引号,并将内部双引号替换为 `""`。
### 5.2 `void WriteAll(IEnumerable<IEnumerable<Object?>> data)`
-����д�룺
+逐行写入:
-- �ڲ�ѭ������ `WriteLine(line)`��
+- 内部循环调用 `WriteLine(line)`。
### 5.3 `Task WriteLineAsync(IEnumerable<Object> line)`
-�첽дһ�У���д�����첽����
+异步写一行(仅写入器异步)。
-ע�⣺
+注意:
-- �÷�������Ϊ `IEnumerable<Object>`�������� `null` ���ͬ�� `Object?` ��ͬ����
+- 该方法参数为 `IEnumerable<Object>`,不接受 `null` 项(与同步 `Object?` 不同)。
---
-## 6. ��Сʾ��
+## 6. 最小示例
-### 6.1 ��ȡ CSV
+### 6.1 读取 CSV
```csharp
using NewLife.IO;
@@ -152,60 +152,60 @@ while (true)
var row = csv.ReadLine();
if (row == null) break;
- // row ���ֶ�����
- // ���磺row[0], row[1] ...
+ // row 是字段数组
+ // 例如:row[0], row[1] ...
}
```
-### 6.2 � CSV�������
+### 6.2 写入 CSV(覆盖写)
```csharp
using NewLife.IO;
using var csv = new CsvFile("./out.csv", write: true);
-// ֱ��д��
+// 直接写入
csv.WriteLine("Id", "Name", "Remark");
csv.WriteLine(1, "Stone", "hello,world");
```
-### 6.3 ���������
+### 6.3 追加写(增量)
```csharp
using NewLife.IO;
using var csv = new CsvFile("./out.csv", write: true);
-// ���캯�� write:true �� ReadWrite ���Ҳ��ض�
-// ��Ҫ�ӵ�β���������ж�λ
-// ��Ҳ���� FileStream + CsvFile(stream, true) ����
+// 构造函数 write:true 以 ReadWrite 打开且不截断
+// 若要追加到尾部,可自行定位
+// (也可用 FileStream + CsvFile(stream, true) 更灵活)
csv.WriteLine(DateTime.Now, true, "append");
```
---
-## 7. ע�������볣������
+## 7. 注意事项与常见问题
-### 7.1 ��ȡ���ǰ��������С����ǰ�����¼��
+### 7.1 读取不是按“物理行”而是按“记录”
-���ֶα�˫���Ű������ڲ�������ʱ��`ReadLine()` ���Խ���ж������űպ�Ϊֹ������ CSV ������ȷ����Ϊ��
+当字段被双引号包裹且内部含换行时,`ReadLine()` 会跨越多行读到引号闭合为止,这是 CSV 语义正确的行为。
-### 7.2 `Separator` ��Ϊ�Ʊ�����TSV��
+### 7.2 `Separator` 改为制表符(TSV)
```csharp
var csv = new CsvFile(file) { Separator = '\t' };
```
-д��ʱ��ݴ��ж��Ƿ���Ҫ���š�
+写入时会据此判断是否需要引号。
-### 7.3 ����ѡ��
+### 7.3 编码选择
-- Excel ��ijЩ�����¶� UTF-8 �� BOM ʶ�ѣ�����Ҫ���ݣ��ɿ���д��ǰ������� BOM ����� `Encoding.UTF8` �� BOM �İ汾���ɵ��÷�������д�룩��
+- Excel 在某些环境下对 UTF-8 无 BOM 识别不佳;若需要兼容,可考虑写入前自行输出 BOM 或改用 `Encoding.UTF8` 带 BOM 的版本(由调用方控制流写入)。
---
-## 8. �������
+## 8. 相关链接
-- �����ĵ���`https://newlifex.com/core/csv_file`
-- Դ�룺`NewLife.Core/IO/CsvFile.cs`
+- 在线文档:`https://newlifex.com/core/csv_file`
+- 源码:`NewLife.Core/IO/CsvFile.cs`
diff --git "a/Doc/Excel\350\257\273\345\217\226\345\231\250ExcelReader.md" "b/Doc/Excel\350\257\273\345\217\226\345\231\250ExcelReader.md"
index 150b985..30a652f 100644
--- "a/Doc/Excel\350\257\273\345\217\226\345\231\250ExcelReader.md"
+++ "b/Doc/Excel\350\257\273\345\217\226\345\231\250ExcelReader.md"
@@ -1,173 +1,173 @@
-# ExcelReader ʹ���ֲ�
+# ExcelReader 使用手册
-���ĵ�����Դ�� `NewLife.Core/IO/ExcelReader.cs`������˵�� `ExcelReader`�������� Excel xlsx ��ȡ�����Ķ�λ��֧�ַ�Χ�����ݶ�ȡ��ʽ������ת��������ʹ��ע�����
+本文档基于源码 `NewLife.Core/IO/ExcelReader.cs`,用于说明 `ExcelReader`(轻量级 Excel xlsx 读取器)的定位、支持范围、数据读取方式、类型转换规则与使用注意事项。
-> �ؼ��ʣ�xlsx��ZipArchive��sharedStrings��styles��sheetData�������� AA/AB��ȱʧ�в��롢��ֵ��ʽ��
+> 关键词:xlsx、ZipArchive、sharedStrings、styles、sheetData、列索引 AA/AB、缺失列补齐、数值格式。
---
-## 1. ����
+## 1. 概述
-`ExcelReader` ��һ�������ڡ��������ݡ��������� xlsx ��ȡ����
+`ExcelReader` 是一个仅用于“导入数据”的轻量级 xlsx 读取器。
-- ��֧�� `xlsx`��OpenXML���������� zip ѹ������
-- ������������ Office/Interop �����
-- ��ǰʵ��ֻ����С��������
- - �����ַ�����`xl/sharedStrings.xml`��
- - ��ʽ��`xl/styles.xml`�����ָ�ʽ��
- - ���������ݣ�`xl/worksheets/sheet*.xml` �е� `sheetData`��
+- 仅支持 `xlsx`(OpenXML),本质是 zip 压缩包;
+- 不依赖第三方 Office/Interop 组件;
+- 当前实现只做最小化解析:
+ - 共享字符串(`xl/sharedStrings.xml`)
+ - 样式(`xl/styles.xml`,数字格式)
+ - 工作表数据(`xl/worksheets/sheet*.xml` 中的 `sheetData`)
-������
+适用场景:
-- ������/������������� Excel��
-- ֻ��Ҫ�ѹ��������ж�ȡ�ɶ������飻
-- ����ע��ʽ���㡢�ϲ���Ԫ��ͼ������ע�ȸ������ԡ�
+- 服务器/桌面端批量导入 Excel;
+- 只需要把工作表按行读取成对象数组;
+- 不关注公式计算、合并单元格、图表、批注等复杂特性。
---
-## 2. ��������Դ����
+## 2. 构造与资源管理
### 2.1 `ExcelReader(String fileName)`
-- �Թ�����ʽ���ļ���`FileShare.ReadWrite`�������ļ�����������ռ��ʱ������
-- �� `ZipArchive` ��ȡ zip ���ݣ�
-- ���캯������������ `Parse()` ������Ҫ��������
+- 以共享方式打开文件:`FileShare.ReadWrite`,避免文件被其它进程占用时报错;
+- 用 `ZipArchive` 读取 zip 内容;
+- 构造函数会立即调用 `Parse()` 解析必要的索引。
### 2.2 `ExcelReader(Stream stream, Encoding encoding)`
-- ���� xlsx �����������÷��������������ڣ��豣�ֿɶ�����
-- `encoding` ���� zip ��Ŀ����/ע�͵ȱ��루һ��Ϊ UTF-8����
+- 传入 xlsx 数据流(调用方负责流生命周期,需保持可读);
+- `encoding` 用于 zip 条目名称/注释等编码(一般为 UTF-8)。
### 2.3 Dispose
-`ExcelReader` �̳� `DisposeBase`��
+`ExcelReader` 继承 `DisposeBase`:
-- `Dispose(Boolean)` ������ `_entries` ���ͷ� `_zip`��
-- ���ͬʱ�ͷ���ײ� `FileStream`�����ɹ��캯����������
+- `Dispose(Boolean)` 会清理 `_entries` 并释放 `_zip`;
+- 这会同时释放其底层 `FileStream`(若由构造函数创建)。
-���飺
+建议:
-- ʼ��ʹ�� `using var reader = new ExcelReader(...)`��
+- 始终使用 `using var reader = new ExcelReader(...)`。
---
-## 3. ��������
+## 3. 基本属性
### 3.1 `FileName`
-- ���ͣ�`String?`
-- ���ļ����캯��ֱ�Ӹ�ֵ��
-- �������캯���У��� `stream is FileStream` ʱȡ `fs.Name`��
+- 类型:`String?`
+- 从文件构造函数直接赋值;
+- 从流构造函数中,当 `stream is FileStream` 时取 `fs.Name`。
### 3.2 `Sheets`
-- ���ͣ�`ICollection<String>?`
-- ���壺���ù��������Ƽ��ϣ������� `_entries.Keys`����
+- 类型:`ICollection<String>?`
+- 语义:可用工作表名称集合(键来自 `_entries.Keys`)。
-˵����
+说明:
-- `Parse()` ��ѹ���������ӳ�䵽��Ӧ `ZipArchiveEntry`��
+- `Parse()` 会把工作表名称映射到对应 `ZipArchiveEntry`。
---
-## 4. ��ȡ����
+## 4. 读取数据
### 4.1 `IEnumerable<Object?[]> ReadRows(String? sheet = null)`
-���з������ݣ���һ��ͨ���DZ�ͷ����
+按行返回数据(第一行通常是表头):
-- `sheet=null` ʱĬ��ȡ `Sheets.FirstOrDefault()`��
-- �Ҳ������������� `ArgumentOutOfRangeException`��
-- ��ȡ���̣�
- 1. ��Ŀ�� sheet ��Ŀ����
- 2. `XDocument.Load` ��ȡ XML��
- 3. �ڸ��ڵ����� `sheetData`��
- 4. ����ÿ�� `<row>`�������� `<c>` ��Ԫ����н�����
+- `sheet=null` 时默认取 `Sheets.FirstOrDefault()`;
+- 找不到工作表会抛 `ArgumentOutOfRangeException`;
+- 读取流程:
+ 1. 打开目标 sheet 条目流;
+ 2. `XDocument.Load` 读取 XML;
+ 3. 在根节点下找 `sheetData`;
+ 4. 遍历每个 `<row>`,对下面 `<c>` 单元格进行解析。
-����ֵ��
+返回值:
-- ÿһ����һ�� `Object?[]`��
-- ֵ���ܱ�ת��Ϊ��`DateTime` / `TimeSpan` / `Int32` / `Int64` / `Decimal` / `Double` / `Boolean` / `String`��
-- ��ֵ��ȱʧ���� `null` ��ʾ��
+- 每一行是一个 `Object?[]`;
+- 值可能被转换为:`DateTime` / `TimeSpan` / `Int32` / `Int64` / `Decimal` / `Double` / `Boolean` / `String`;
+- 无值或缺失列以 `null` 表示。
-### 4.2 �ؼ���Ϊ����������ȱʧ�в���
+### 4.2 关键行为:列索引与缺失列补齐
-Excel ��Ԫ�������� `A1`��`AB23`��ʵ�ֻ
+Excel 单元格引用如 `A1`、`AB23`;实现会:
-- ��������ĸΪ 0 ��������`A=0`��`B=1`��`AA=26`����
-- �����г������У�����ֻ�� A��C�������Զ��� B ��Ϊ `null`��
-- ���¼�������� `headerColumnCount`����������β����ȱʧҲ�Ჹ�뵽������һ�¡�
+- 解析列字母为 0 基索引(`A=0`,`B=1`,`AA=26`);
+- 若本行出现跳列(例如只有 A、C),会自动把 B 补为 `null`;
+- 会记录首行列数 `headerColumnCount`,后续行若尾部列缺失也会补齐到与首行一致。
-��ʹ�ã�
+这使得:
-- ��ȡ������ӽ�����ά����ֱ�۽ṹ��
-- ����ֱ�Ӱ����������ʡ�
+- 读取结果更接近“二维表格”的直观结构;
+- 便于直接按列索引访问。
---
-## 5. ��Ԫ�����ͽ�����ת������
+## 5. 单元格类型解析与转换规则
-### 5.1 �����ַ�����`t="s"`��
+### 5.1 共享字符串(`t="s"`)
-����Ԫ������ `t="s"`��
+当单元格属性 `t="s"`:
-- `<v>` �洢���ǹ����ַ���������
-- �ᵽ `_sharedStrings[sharedIndex]` ȡ��ʵ�ı���
+- `<v>` 存储的是共享字符串索引;
+- 会到 `_sharedStrings[sharedIndex]` 取真实文本。
-�����ַ������� `xl/sharedStrings.xml`������Ŀ����ȱʧ����������
+共享字符串来自 `xl/sharedStrings.xml`,该条目可能缺失(允许)。
-### 5.2 ������`t="b"`��
+### 5.2 布尔(`t="b"`)
-- `0/1` �� `true/false`��
-- תΪ `Boolean`��
+- `0/1` 或 `true/false`;
+- 转为 `Boolean`。
-### 5.3 ��ʽ����ı���`t="str"`��
+### 5.3 公式结果文本(`t="str"`)
-- �����������ֱ��ȡ�ı�ֵ��
+- 不做特殊处理,直接取文本值。
-### 5.4 ����/����/ʱ�䣺��ʽ����ת��
+### 5.4 数字/日期/时间:样式驱动转换
-����Ԫ��ֵΪ�ַ����Ҵ�����ʽ `_styles` ʱ��
+当单元格值为字符串且存在样式 `_styles` 时:
-- ��ȡ��Ԫ������ `s`��StyleIndex����
-- ���� `styles[si]` �� `NumFmtId/Format` ����ת�����ԡ�
+- 读取单元格属性 `s`(StyleIndex);
+- 根据 `styles[si]` 的 `NumFmtId/Format` 决定转换策略。
-ת����λ�� `ChangeType(Object? val, ExcelNumberFormat st)`��
+转换逻辑位于 `ChangeType(Object? val, ExcelNumberFormat st)`:
-- **����/ʱ��**��
- - ��������ʽ���� `yy`/`mmm` �� `NumFmtId` �� 14~17 ��Ϊ 22��
- - Excel ����ֵ�� 1900-01-01 Ϊ������ʷ����ʵ�ֻ��� `d-2` ������
- - ʹ�� `AddSeconds(Math.Round((d - 2) * 24 * 3600))`��������ܸ�����
+- **日期/时间**:
+ - 条件:格式包含 `yy`/`mmm` 或 `NumFmtId` 在 14~17 或为 22;
+ - Excel 序列值以 1900-01-01 为基准,历史兼容实现会做 `d-2` 调整;
+ - 使用 `AddSeconds(Math.Round((d - 2) * 24 * 3600))`,尽量规避浮点误差。
-- **ʱ����**��TimeSpan����
- - ������`NumFmtId` �� 18~21 �� 45~47��
- - תΪ `TimeSpan.FromSeconds(Math.Round(d2 * 24 * 3600))`��
+- **时间间隔**(TimeSpan):
+ - 条件:`NumFmtId` 在 18~21 或 45~47;
+ - 转为 `TimeSpan.FromSeconds(Math.Round(d2 * 24 * 3600))`。
-- **General / 0**��
- - ������`NumFmtId == 0`��
- - ����� `Int32`��`Int64`��`Decimal(InvariantCulture)`��`Double`��
+- **General / 0**:
+ - 条件:`NumFmtId == 0`;
+ - 依次尝试 `Int32`、`Int64`、`Decimal(InvariantCulture)`、`Double`。
-- **������ʽ**��
- - ������`NumFmtId` Ϊ 1/3/37/38��
- - ���� `Int32/Int64`��
+- **整数格式**:
+ - 条件:`NumFmtId` 为 1/3/37/38;
+ - 尝试 `Int32/Int64`。
-- **С����ʽ**��
- - ������`NumFmtId` Ϊ 2/4/11/39/40��
- - ���� `Decimal(InvariantCulture)` �� `Double`��
+- **小数格式**:
+ - 条件:`NumFmtId` 为 2/4/11/39/40;
+ - 尝试 `Decimal(InvariantCulture)` 或 `Double`。
-- **�ٷֱ�**��
- - ������`NumFmtId` Ϊ 9/10��
- - ���� `Double`��ע�⣺�õ����� 0.x���� 12% => 0.12����
+- **百分比**:
+ - 条件:`NumFmtId` 为 9/10;
+ - 尝试 `Double`(注意:得到的是 0.x,如 12% => 0.12)。
-- **�ı���ʽ**��
- - ������`NumFmtId == 49`��
- - ���ɽ���Ϊ��ֵ����ת���ַ����������ʱ������ֵ���ͣ���
+- **文本格式**:
+ - 条件:`NumFmtId == 49`;
+ - 若可解析为数值则再转回字符串(避免导入时进入数值类型)。
---
-## 6. ��Сʾ��
+## 6. 最小示例
-### 6.1 ��ȡ��һ��������
+### 6.1 读取第一个工作表
```csharp
using NewLife.IO;
@@ -176,12 +176,12 @@ using var reader = new ExcelReader("./data.xlsx");
foreach (var row in reader.ReadRows())
{
- // ��һ��ͨ���DZ�ͷ
- // row[i] ������ String/Int32/DateTime/Boolean/TimeSpan/null
+ // 第一行通常是表头
+ // row[i] 可能是 String/Int32/DateTime/Boolean/TimeSpan/null
}
```
-### 6.2 ָ������������
+### 6.2 指定工作表名称
```csharp
using var reader = new ExcelReader("./data.xlsx");
@@ -195,7 +195,7 @@ if (!sheet.IsNullOrEmpty())
}
```
-### 6.3 �� `CsvFile` ��ϣ�Excel ת CSV
+### 6.3 与 `CsvFile` 组合:Excel 转 CSV
```csharp
using NewLife.IO;
@@ -211,33 +211,33 @@ foreach (var row in reader.ReadRows())
---
-## 7. ע�������볣������
+## 7. 注意事项与常见问题
-### 7.1 ֻ��ȡ `sheetData`
+### 7.1 只读取 `sheetData`
-��ʵ��ֻ��ȡ `sheetData`�����������
+本实现只读取 `sheetData`,不会解析:
-- �ϲ���Ԫ��mergedCells��
-- ��ʽ���㣨ֻ�������
-- ͼƬ/ͼ��/��ע
+- 合并单元格(mergedCells)
+- 公式计算(只读结果)
+- 图片/图表/批注
-����Ҫ��չ���ɸ��� OpenXML �ṹ���� `ZipArchive` ��Ŀ����������
+若需要扩展,可根据 OpenXML 结构基于 `ZipArchive` 条目继续解析。
-### 7.2 �ڴ�ռ��
+### 7.2 内存占用
-��ǰʵ�ֶ�ÿ�� `ReadRows()`��
+当前实现对每次 `ReadRows()`:
-- �� `XDocument.Load` ������ sheet XML �����ڴ档
+- 会 `XDocument.Load` 把整个 sheet XML 载入内存。
-�Գ�����������ռ�ý϶��ڴ棻��Ҫ֧�ָ����ļ�����Ҫ��Ϊ `XmlReader` ��ʽ���������ڹ�����չ�����ڱ��ĵ���Χ����
+对超大工作表可能占用较多内存;若要支持更大文件,需要改为 `XmlReader` 流式解析(属于功能扩展,不在本文档范围)。
-### 7.3 ����ƫ�ƣ��� 2��
+### 7.3 日期偏移(减 2)
-Դ���ж� Excel ��������ֵʹ�� `d - 2` ����ʷ������Ϊ������ƥ�������û���������������ھ������ϸ�Ҫ����Ҫ��Ͼ���������֤��
+源码中对 Excel 日期序列值使用 `d - 2` 的历史兼容行为,用于匹配现有用户期望。若你对日期精度有严格要求,需要结合具体样例验证。
---
-## 8. �������
+## 8. 相关链接
-- �����ĵ���`https://newlifex.com/core/excel_reader`
-- Դ�룺`NewLife.Core/IO/ExcelReader.cs`
+- 在线文档:`https://newlifex.com/core/excel_reader`
+- 源码:`NewLife.Core/IO/ExcelReader.cs`
diff --git "a/Doc/HTTP\345\256\242\346\210\267\347\253\257ApiHttpClient.md" "b/Doc/HTTP\345\256\242\346\210\267\347\253\257ApiHttpClient.md"
index 380cecd..c510316 100644
--- "a/Doc/HTTP\345\256\242\346\210\267\347\253\257ApiHttpClient.md"
+++ "b/Doc/HTTP\345\256\242\346\210\267\347\253\257ApiHttpClient.md"
@@ -1,86 +1,86 @@
-# ApiHttpClient ʹ���ֲ�
+# ApiHttpClient 使用手册
-## ����
+## 概述
-`ApiHttpClient` �� NewLife.Core �ṩ�� Http Ӧ�ýӿڿͻ��ˣ��ǶԶ�������ַ�İ�װ�����ڵײ������� `HttpClient`���ṩͳһ�ĸ��ؾ������ת��������
+`ApiHttpClient` 是 NewLife.Core 提供的 Http 应用接口客户端,是对多个服务地址的包装。它在底层管理多个 `HttpClient`,提供统一的负载均衡和故障转移能力。
-### ��������
+### 核心特性
-- **���ַ����**��֧�����ö�������ַ���Զ����и��ؾ���
-- **����ת��**���ڵ㲻����ʱ�Զ��л������ýڵ�
-- **���ؾ���**��֧�ֹ���ת�ơ���Ȩ��ѯ�����ٵ�������ģʽ
-- **���Ƽ�Ȩ**��֧�� Token �� Authentication ���ּ�Ȩ��ʽ
-- **��Ӧ����**��֧���Զ���״̬��������ֶ����ƣ����䲻ͬƽ̨
-- **����չ��**��֧���Զ��� JsonHost��Filter���¼���
+- **多地址管理**:支持配置多个服务地址,自动进行负载均衡
+- **故障转移**:节点不可用时自动切换到备用节点
+- **负载均衡**:支持故障转移、加权轮询、竞速调用三种模式
+- **令牌鉴权**:支持 Token 和 Authentication 两种鉴权方式
+- **响应解析**:支持自定义状态码和数据字段名称,适配不同平台
+- **可扩展性**:支持自定义 JsonHost、Filter、事件等
-## ���ٿ�ʼ
+## 快速开始
-### �����÷�
+### 基础用法
```csharp
-// �����ͻ���
+// 创建客户端
var client = new ApiHttpClient("http://api.example.com");
-// GET ����
+// GET 请求
var result = await client.GetAsync<UserInfo>("user/info", new { id = 123 });
-// POST ����
+// POST 请求
var response = await client.PostAsync<ResultModel>("user/create", new { name = "test", age = 18 });
-// ͬ������
+// 同步调用
var data = client.Get<String>("api/data");
```
-### ���ַ����
+### 多地址配置
```csharp
-// ���ŷָ������ַ
+// 逗号分隔多个地址
var client = new ApiHttpClient("http://api1.example.com,http://api2.example.com,http://api3.example.com");
-// �����ֶ�����
+// 或者手动添加
var client = new ApiHttpClient();
client.Add("primary", "http://api1.example.com");
client.Add("backup", "http://api2.example.com");
```
-## ���ؾ���
+## 负载均衡
-### ���ָ��ؾ���ģʽ
+### 三种负载均衡模式
-| ģʽ | ö��ֵ | ˵�� |
+| 模式 | 枚举值 | 说明 |
|------|--------|------|
-| ����ת�� | `LoadBalanceMode.Failover` | ����ʹ�����ڵ㣬ʧ��ʱ�Զ��л������ýڵ㣬��һ��ʱ���Զ��л� |
-| ��Ȩ��ѯ | `LoadBalanceMode.RoundRobin` | ��Ȩ�ط���������ڵ㣬�Զ����β����ýڵ� |
-| ���ٵ��� | `LoadBalanceMode.Race` | �����������ڵ㣬ȡ�����Ӧ��ȡ���������� |
+| 故障转移 | `LoadBalanceMode.Failover` | 优先使用主节点,失败时自动切换到备用节点,过一段时间自动切回 |
+| 加权轮询 | `LoadBalanceMode.RoundRobin` | 按权重分配请求到多个节点,自动屏蔽不可用节点 |
+| 竞速调用 | `LoadBalanceMode.Race` | 并行请求多个节点,取最快响应,取消其它请求 |
-### ����ת��ģʽ��Ĭ�ϣ�
+### 故障转移模式(默认)
```csharp
var client = new ApiHttpClient("http://primary.example.com,http://backup.example.com")
{
- LoadBalanceMode = LoadBalanceMode.Failover, // Ĭ��ֵ
- ShieldingTime = 60 // �����ýڵ�����60��
+ LoadBalanceMode = LoadBalanceMode.Failover, // 默认值
+ ShieldingTime = 60 // 不可用节点屏蔽60秒
};
-// �������ʹ�� primary��primary ������ʱ�Զ��л��� backup
-// 60���᳢���л� primary
+// 正常情况使用 primary,primary 不可用时自动切换到 backup
+// 60秒后会尝试切回 primary
var result = await client.GetAsync<Object>("api/data");
```
-### ��Ȩ��ѯģʽ
+### 加权轮询模式
```csharp
-// ��ʽ��name=weight*url
+// 格式:name=weight*url
var client = new ApiHttpClient("master=3*http://api1.example.com,slave=7*http://api2.example.com")
{
LoadBalanceMode = LoadBalanceMode.RoundRobin
};
-// master Ȩ��3��slave Ȩ��7
-// 10�������У�master Լ3�Σ�slave Լ7��
+// master 权重3,slave 权重7
+// 10次请求中,master 约3次,slave 约7次
```
-### ���ٵ���ģʽ
+### 竞速调用模式
```csharp
var client = new ApiHttpClient("http://api1.example.com,http://api2.example.com,http://api3.example.com")
@@ -88,13 +88,13 @@ var client = new ApiHttpClient("http://api1.example.com,http://api2.example.com,
LoadBalanceMode = LoadBalanceMode.Race
};
-// �����������нڵ㣬����������Ӧ
-// �����ڶ���Ӧʱ��Ҫ�ߵij���
+// 并行请求所有节点,返回最快的响应
+// 适用于对响应时间要求极高的场景
```
-## ������֤
+## 身份验证
-### Token ����
+### Token 令牌
```csharp
var client = new ApiHttpClient("http://api.example.com")
@@ -102,10 +102,10 @@ var client = new ApiHttpClient("http://api.example.com")
Token = "your_access_token"
};
-// ����ͷ�Զ����ӣ�Authorization: Bearer your_access_token
+// 请求头自动添加:Authorization: Bearer your_access_token
```
-### Authentication ����
+### Authentication 属性
```csharp
var client = new ApiHttpClient("http://api.example.com")
@@ -113,27 +113,27 @@ var client = new ApiHttpClient("http://api.example.com")
Authentication = new AuthenticationHeaderValue("Bearer", "your_token")
};
-// ����ʹ�� Basic ��֤
+// 或者使用 Basic 认证
client.Authentication = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.UTF8.GetBytes("user:password")));
```
-### ����ڵ���� Token
+### 服务节点独立 Token
```csharp
-// �� URL ��ָ�� Token
+// 在 URL 中指定 Token
var client = new ApiHttpClient();
client.Add("service1", "http://api1.example.com#token=token_for_api1");
client.Add("service2", "http://api2.example.com#token=token_for_api2");
```
-> **���ȼ�**��`Token` ���������� `Authentication` ���ԡ�
+> **优先级**:`Token` 属性优先于 `Authentication` 属性。
-## ��Ӧ����
+## 响应解析
-### ����Ӧ��ʽ
+### 标准响应格式
-Ĭ��֧��������Ӧ��ʽ��
+默认支持以下响应格式:
```json
{
@@ -143,40 +143,40 @@ client.Add("service2", "http://api2.example.com#token=token_for_api2");
}
```
-### �Զ����ֶ�����
+### 自定义字段名称
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
- CodeName = "status", // ״̬���ֶ�����Ĭ���Զ�ʶ�� code/errcode/status
- DataName = "result" // �����ֶ�����Ĭ�� data
+ CodeName = "status", // 状态码字段名,默认自动识别 code/errcode/status
+ DataName = "result" // 数据字段名,默认 data
};
-// ������Ӧ��ʽ��{"status": 0, "result": {...}}
+// 适配响应格式:{"status": 0, "result": {...}}
```
-### ֧�ֵ�״̬���ֶ�
+### 支持的状态码字段
- `code`
- `errcode`
- `status`
-### ֧�ֵ���Ϣ�ֶ�
+### 支持的消息字段
- `message`
- `msg`
- `errmsg`
- `error`
-## Http ����
+## Http 方法
```csharp
var client = new ApiHttpClient("http://api.example.com");
-// GET - ����ƴ�ӵ� URL
+// GET - 参数拼接到 URL
var result = await client.GetAsync<T>("api/users", new { page = 1, size = 10 });
-// POST - ���� JSON ����� Body
+// POST - 参数 JSON 序列化到 Body
var result = await client.PostAsync<T>("api/users", new { name = "test" });
// PUT
@@ -188,40 +188,40 @@ var result = await client.PatchAsync<T>("api/users/1", new { name = "patched" })
// DELETE
var result = await client.DeleteAsync<T>("api/users/1");
-// ͨ�õ���
+// 通用调用
var result = await client.InvokeAsync<T>(HttpMethod.Post, "api/action", args);
```
-## ������
+## 高级配置
-### ��ʱ����
+### 超时设置
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
- Timeout = 30_000 // 30�룬Ĭ��15��
+ Timeout = 30_000 // 30秒,默认15秒
};
```
-### ��������
+### 代理设置
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
- UseProxy = true // ʹ��ϵͳ������Ĭ��false
+ UseProxy = true // 使用系统代理,默认false
};
```
-### SSL֤����֤
+### SSL证书验证
```csharp
var client = new ApiHttpClient("https://api.example.com")
{
- CertificateValidation = false // ����֤֤�飬Ĭ��false
+ CertificateValidation = false // 不验证证书,默认false
};
```
-### �Զ��� UserAgent
+### 自定义 UserAgent
```csharp
var client = new ApiHttpClient("http://api.example.com")
@@ -230,44 +230,44 @@ var client = new ApiHttpClient("http://api.example.com")
};
```
-### �Զ��� Json ���л�
+### 自定义 Json 序列化
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
- JsonHost = new FastJson() // �Զ��� Json ���л���
+ JsonHost = new FastJson() // 自定义 Json 序列化器
};
```
-## �¼��������
+## 事件与过滤器
-### OnRequest �¼�
+### OnRequest 事件
```csharp
var client = new ApiHttpClient("http://api.example.com");
client.OnRequest += (sender, e) =>
{
- // �����Զ�������ͷ
+ // 添加自定义请求头
e.Request.Headers.Add("X-Request-Id", Guid.NewGuid().ToString());
e.Request.Headers.Add("X-Timestamp", DateTime.Now.Ticks.ToString());
};
```
-### OnCreateClient �¼�
+### OnCreateClient 事件
```csharp
client.OnCreateClient += (sender, e) =>
{
- // ���� HttpClient
+ // 配置 HttpClient
e.Client.DefaultRequestHeaders.Add("X-App-Version", "1.0.0");
};
```
-### Http ������
+### Http 过滤器
```csharp
-// ʹ�����õ����ƹ�����
+// 使用内置的令牌过滤器
var filter = new TokenHttpFilter
{
UserName = "app_id",
@@ -279,81 +279,81 @@ var client = new ApiHttpClient("http://api.example.com")
Filter = filter
};
-// ���������Զ��������ƵĻ�ȡ��ˢ��
+// 过滤器会自动处理令牌的获取和刷新
```
-### �Զ��������
+### 自定义过滤器
```csharp
public class MyHttpFilter : IHttpFilter
{
public Task OnRequest(HttpClient client, HttpRequestMessage request, Object? state, CancellationToken cancellationToken)
{
- // ����ǰ����
+ // 请求前处理
request.Headers.Add("X-Custom", "value");
return Task.CompletedTask;
}
public Task OnResponse(HttpClient client, HttpResponseMessage response, Object? state, CancellationToken cancellationToken)
{
- // ��Ӧ����
+ // 响应后处理
return Task.CompletedTask;
}
public Task OnError(HttpClient client, Exception ex, Object? state, CancellationToken cancellationToken)
{
- // ������
+ // 错误处理
return Task.CompletedTask;
}
}
```
-## ����״̬���
+## 服务状态监控
-### �鿴��ǰ����
+### 查看当前服务
```csharp
var client = new ApiHttpClient("http://api1.example.com,http://api2.example.com");
-// ��ǰ����ʹ�õķ���
+// 当前正在使用的服务
var current = client.Current;
-Console.WriteLine($"��ǰ����{current?.Name} - {current?.Address}");
+Console.WriteLine($"当前服务:{current?.Name} - {current?.Address}");
-// ��ǰ��������
-Console.WriteLine($"����Դ��{client.Source}");
+// 当前服务名称
+Console.WriteLine($"服务源:{client.Source}");
```
-### �鿴�����б�״̬
+### 查看服务列表状态
```csharp
foreach (var svc in client.Services)
{
- Console.WriteLine($"����{svc.Name}");
- Console.WriteLine($" ��ַ��{svc.Address}");
- Console.WriteLine($" Ȩ�أ�{svc.Weight}");
- Console.WriteLine($" ������{svc.Times}");
- Console.WriteLine($" ���������{svc.Errors}");
- Console.WriteLine($" �Ƿ���ã�{svc.IsAvailable()}");
- Console.WriteLine($" �´ο���ʱ�䣺{svc.NextTime}");
+ Console.WriteLine($"服务:{svc.Name}");
+ Console.WriteLine($" 地址:{svc.Address}");
+ Console.WriteLine($" 权重:{svc.Weight}");
+ Console.WriteLine($" 调用次数:{svc.Times}");
+ Console.WriteLine($" 错误次数:{svc.Errors}");
+ Console.WriteLine($" 是否可用:{svc.IsAvailable()}");
+ Console.WriteLine($" 下次可用时间:{svc.NextTime}");
}
```
-## ��·��
+## 链路追踪
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
- Tracer = DefaultTracer.Instance, // ������·����
- SlowTrace = 5_000 // ����5���¼��������־
+ Tracer = DefaultTracer.Instance, // 设置链路追踪器
+ SlowTrace = 5_000 // 超过5秒记录慢调用日志
};
```
-## ����ע��
+## 依赖注入
-### ASP.NET Core ����
+### ASP.NET Core 集成
```csharp
-// ע�����
+// 注册服务
services.AddSingleton<IApiClient>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
@@ -365,38 +365,38 @@ services.AddSingleton<IApiClient>(sp =>
return client;
});
-// ʹ����������
+// 使用配置中心
services.AddSingleton<IApiClient>(sp =>
{
- return new ApiHttpClient(sp, "ApiServerConfig"); // ���������Ķ�ȡ
+ return new ApiHttpClient(sp, "ApiServerConfig"); // 从配置中心读取
});
```
-### IConfigMapping �ӿ�
+### IConfigMapping 接口
```csharp
-// ApiHttpClient ʵ���� IConfigMapping �ӿ�
-// ����ͨ���������Ķ�̬���·����ַ
+// ApiHttpClient 实现了 IConfigMapping 接口
+// 可以通过配置中心动态更新服务地址
var configProvider = services.GetRequiredService<IConfigProvider>();
-configProvider.Bind(client, true, "ApiServer"); // �����ý�
+configProvider.Bind(client, true, "ApiServer"); // 绑定配置节
```
-## �����
+## 文件下载
```csharp
var client = new ApiHttpClient("http://download.example.com");
-// �����ļ���У���ϣ
+// 下载文件并校验哈希
await client.DownloadFileAsync(
requestUri: "files/package.zip",
fileName: "D:/downloads/package.zip",
- expectedHash: "sha256:abc123...", // ��ѡ��֧�� md5/sha1/sha256/sha512
+ expectedHash: "sha256:abc123...", // 可选,支持 md5/sha1/sha256/sha512
cancellationToken: default
);
```
-## �쳣����
+## 异常处理
### ApiException
@@ -407,23 +407,23 @@ try
}
catch (ApiException ex)
{
- // ҵ���쳣������˷��صĴ����룩
- Console.WriteLine($"�����룺{ex.Code}");
- Console.WriteLine($"������Ϣ��{ex.Message}");
+ // 业务异常(服务端返回的错误码)
+ Console.WriteLine($"错误码:{ex.Code}");
+ Console.WriteLine($"错误信息:{ex.Message}");
}
catch (HttpRequestException ex)
{
- // �����쳣
- Console.WriteLine($"�������{ex.Message}");
+ // 网络异常
+ Console.WriteLine($"网络错误:{ex.Message}");
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ���ÿͻ���ʵ��
+### 1. 复用客户端实例
```csharp
-// ? �Ƽ�����Ϊ����ʹ��
+// ? 推荐:作为单例使用
public class MyService
{
private static readonly ApiHttpClient _client = new("http://api.example.com");
@@ -431,51 +431,51 @@ public class MyService
public Task<T> GetDataAsync<T>() => _client.GetAsync<T>("api/data");
}
-// ? ���⣺ÿ��������ʵ��
+// ? 避免:每次请求创建新实例
public async Task<T> GetDataAsync<T>()
{
- using var client = new ApiHttpClient("http://api.example.com"); // ���Ƽ�
+ using var client = new ApiHttpClient("http://api.example.com"); // 不推荐
return await client.GetAsync<T>("api/data");
}
```
-### 2. �������ó�ʱ
+### 2. 合理设置超时
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
- Timeout = 10_000, // ���ݽӿ��������ú�����ʱ
- SlowTrace = 3_000 // ��������ֵ
+ Timeout = 10_000, // 根据接口特性设置合理超时
+ SlowTrace = 3_000 // 慢调用阈值
};
```
-### 3. ���ù���ת��
+### 3. 配置故障转移
```csharp
var client = new ApiHttpClient("http://primary.example.com,http://backup.example.com")
{
- ShieldingTime = 30, // ���Ͻڵ�����30��
+ ShieldingTime = 30, // 故障节点屏蔽30秒
LoadBalanceMode = LoadBalanceMode.Failover
};
```
-### 4. ʹ����·��
+### 4. 使用链路追踪
```csharp
var client = new ApiHttpClient("http://api.example.com")
{
Tracer = DefaultTracer.Instance,
- Log = XTrace.Log // ������־
+ Log = XTrace.Log // 开启日志
};
```
-## ����ʾ��
+## 完整示例
```csharp
using NewLife.Log;
using NewLife.Remoting;
-// �����ͻ���
+// 创建客户端
var client = new ApiHttpClient("master=3*http://api1.example.com,slave=7*http://api2.example.com")
{
Token = "your_access_token",
@@ -488,7 +488,7 @@ var client = new ApiHttpClient("master=3*http://api1.example.com,slave=7*http://
Log = XTrace.Log
};
-// ������������
+// 添加请求拦截
client.OnRequest += (sender, e) =>
{
e.Request.Headers.Add("X-Request-Id", Guid.NewGuid().ToString());
@@ -496,43 +496,43 @@ client.OnRequest += (sender, e) =>
try
{
- // ��������
+ // 发起请求
var users = await client.GetAsync<List<UserInfo>>("api/users", new { page = 1, size = 10 });
foreach (var user in users)
{
- Console.WriteLine($"�û���{user.Name}");
+ Console.WriteLine($"用户:{user.Name}");
}
- // �鿴��ǰʹ�õķ���
- Console.WriteLine($"�������{client.Source} - {client.Current?.Address}");
+ // 查看当前使用的服务
+ Console.WriteLine($"请求服务:{client.Source} - {client.Current?.Address}");
}
catch (ApiException ex)
{
- Console.WriteLine($"ҵ����� [{ex.Code}]��{ex.Message}");
+ Console.WriteLine($"业务错误 [{ex.Code}]:{ex.Message}");
}
catch (HttpRequestException ex)
{
- Console.WriteLine($"�������{ex.Message}");
+ Console.WriteLine($"网络错误:{ex.Message}");
}
```
-## �������
+## 相关类型
-| ���� | ˵�� |
+| 类型 | 说明 |
|------|------|
-| `ApiHttpClient` | Http Ӧ�ýӿڿͻ��� |
-| `ServiceEndpoint` | ����˵㣬������ַ��Ȩ�ء�״̬����Ϣ |
-| `ILoadBalancer` | ���ؾ������ӿ� |
-| `FailoverLoadBalancer` | ����ת�Ƹ��ؾ����� |
-| `WeightedRoundRobinLoadBalancer` | ��Ȩ��ѯ���ؾ����� |
-| `RaceLoadBalancer` | ���ٸ��ؾ����� |
-| `IHttpFilter` | Http �������ӿ� |
-| `TokenHttpFilter` | ���ƹ����� |
-| `ApiException` | Api ҵ���쳣 |
-
-## �汾��ʷ
-
-- **v11.0+**�����븺�ؾ���ģʽö�٣�֧�־��ٵ���
-- **v10.0+**��֧���Զ��� CodeName/DataName
-- **v9.0+**��֧����·��
+| `ApiHttpClient` | Http 应用接口客户端 |
+| `ServiceEndpoint` | 服务端点,包含地址、权重、状态等信息 |
+| `ILoadBalancer` | 负载均衡器接口 |
+| `FailoverLoadBalancer` | 故障转移负载均衡器 |
+| `WeightedRoundRobinLoadBalancer` | 加权轮询负载均衡器 |
+| `RaceLoadBalancer` | 竞速负载均衡器 |
+| `IHttpFilter` | Http 过滤器接口 |
+| `TokenHttpFilter` | 令牌过滤器 |
+| `ApiException` | Api 业务异常 |
+
+## 版本历史
+
+- **v11.0+**:引入负载均衡模式枚举,支持竞速调用
+- **v10.0+**:支持自定义 CodeName/DataName
+- **v9.0+**:支持链路追踪
diff --git "a/Doc/JSON\345\272\217\345\210\227\345\214\226.md" "b/Doc/JSON\345\272\217\345\210\227\345\214\226.md"
index 58691ca..79e4951 100644
--- "a/Doc/JSON\345\272\217\345\210\227\345\214\226.md"
+++ "b/Doc/JSON\345\272\217\345\210\227\345\214\226.md"
@@ -1,118 +1,118 @@
-# JSON ���л�
+# JSON 序列化
-## ����
+## 概述
-NewLife.Core �ṩ���������� JSON ���л��ͷ����л����ܣ�ͨ�� `JsonHelper` ��չ�������Է���ؽ��ж����� JSON �ַ�����ת�������� `FastJson` ʵ�֣�ͬʱ֧���л��� `System.Text.Json`��
+NewLife.Core 提供了轻量级的 JSON 序列化和反序列化功能,通过 `JsonHelper` 扩展方法可以方便地进行对象与 JSON 字符串的转换。内置 `FastJson` 实现,同时支持切换到 `System.Text.Json`。
-**�����ռ�**��`NewLife.Serialization`
-**�ĵ���ַ**��https://newlifex.com/core/json
+**命名空间**:`NewLife.Serialization`
+**文档地址**:https://newlifex.com/core/json
-## ��������
+## 核心特性
-- **������**������ `FastJson` ʵ�֣����ⲿ����
-- **������**����Գ��������Ż���֧�ֶ����
-- **��չ����**��`ToJson()` �� `ToJsonEntity<T>()` �������
-- **�������**��֧���շ����������Կ�ֵ��������ʽ����
-- **����ת��**���Զ�������������ת��
-- **���л�**��֧���л��� `System.Text.Json` ʵ��
+- **轻量级**:内置 `FastJson` 实现,无外部依赖
+- **高性能**:针对常见场景优化,支持对象池
+- **扩展方法**:`ToJson()` 和 `ToJsonEntity<T>()` 简洁易用
+- **配置灵活**:支持驼峰命名、忽略空值、缩进格式化等
+- **类型转换**:自动处理常见类型转换
+- **可切换**:支持切换到 `System.Text.Json` 实现
-## ���ٿ�ʼ
+## 快速开始
-### ���л�
+### 序列化
```csharp
using NewLife.Serialization;
-// �������л�
-var user = new { Id = 1, Name = "����", Age = 25 };
+// 简单对象序列化
+var user = new { Id = 1, Name = "张三", Age = 25 };
var json = user.ToJson();
-// {"Id":1,"Name":"����","Age":25}
+// {"Id":1,"Name":"张三","Age":25}
-// ��ʽ�����
+// 格式化输出
var jsonIndented = user.ToJson(true);
// {
// "Id": 1,
-// "Name": "����",
+// "Name": "张三",
// "Age": 25
// }
-// �շ�����
+// 驼峰命名
var jsonCamel = user.ToJson(false, true, true);
-// {"id":1,"name":"����","age":25}
+// {"id":1,"name":"张三","age":25}
```
-### �����л�
+### 反序列化
```csharp
using NewLife.Serialization;
-var json = """{"Id":1,"Name":"����","Age":25}""";
+var json = """{"Id":1,"Name":"张三","Age":25}""";
-// �����л�Ϊָ������
+// 反序列化为指定类型
var user = json.ToJsonEntity<User>();
-// �����л�Ϊ��̬�ֵ�
+// 反序列化为动态字典
var dict = json.DecodeJson();
-var name = dict["Name"]; // "����"
+var name = dict["Name"]; // "张三"
```
-## API �ο�
+## API 参考
-### ToJson - ���л�
+### ToJson - 序列化
```csharp
-// �������л�
+// 基础序列化
public static String ToJson(this Object value, Boolean indented = false)
-// ��������
+// 完整参数
public static String ToJson(this Object value, Boolean indented, Boolean nullValue, Boolean camelCase)
-// ʹ�����ö���
+// 使用配置对象
public static String ToJson(this Object value, JsonOptions jsonOptions)
```
-**����˵��**��
-- `indented`���Ƿ�������ʽ����Ĭ�� false
-- `nullValue`���Ƿ������ֵ��Ĭ�� true
-- `camelCase`���Ƿ�ʹ���շ�������Ĭ�� false
+**参数说明**:
+- `indented`:是否缩进格式化,默认 false
+- `nullValue`:是否输出空值,默认 true
+- `camelCase`:是否使用驼峰命名,默认 false
-**ʾ��**��
+**示例**:
```csharp
var obj = new
{
Id = 1,
- Name = "����",
+ Name = "测试",
Description = (String?)null,
CreateTime = DateTime.Now
};
-// Ĭ�����
+// 默认输出
obj.ToJson();
-// {"Id":1,"Name":"����","Description":null,"CreateTime":"2025-01-07 12:00:00"}
+// {"Id":1,"Name":"测试","Description":null,"CreateTime":"2025-01-07 12:00:00"}
-// ���Կ�ֵ
+// 忽略空值
obj.ToJson(false, false, false);
-// {"Id":1,"Name":"����","CreateTime":"2025-01-07 12:00:00"}
+// {"Id":1,"Name":"测试","CreateTime":"2025-01-07 12:00:00"}
-// �շ����� + ��ʽ��
+// 驼峰命名 + 格式化
obj.ToJson(true, true, true);
```
-### ToJsonEntity - �����л�
+### ToJsonEntity - 反序列化
```csharp
-// ���ͷ���
+// 泛型方法
public static T? ToJsonEntity<T>(this String json)
-// ָ������
+// 指定类型
public static Object? ToJsonEntity(this String json, Type type)
```
-**ʾ��**��
+**示例**:
```csharp
-var json = """{"id":1,"name":"����","roles":["admin","user"]}""";
+var json = """{"id":1,"name":"张三","roles":["admin","user"]}""";
-// �����л�Ϊ��
+// 反序列化为类
public class User
{
public Int32 Id { get; set; }
@@ -121,19 +121,19 @@ public class User
}
var user = json.ToJsonEntity<User>();
-Console.WriteLine(user.Name); // ����
+Console.WriteLine(user.Name); // 张三
Console.WriteLine(user.Roles[0]); // admin
```
-### DecodeJson - ����Ϊ�ֵ�
+### DecodeJson - 解析为字典
```csharp
public static IDictionary<String, Object?>? DecodeJson(this String json)
```
-�� JSON �ַ�������Ϊ�ֵ䣬�����ڶ�̬���ʳ�����
+将 JSON 字符串解析为字典,适用于动态访问场景。
-**ʾ��**��
+**示例**:
```csharp
var json = """{"code":0,"data":{"id":1,"name":"test"},"message":"ok"}""";
@@ -143,35 +143,35 @@ var data = dict["data"] as IDictionary<String, Object>;
var id = data["id"].ToInt(); // 1
```
-### JsonOptions - ����ѡ��
+### JsonOptions - 配置选项
```csharp
public class JsonOptions
{
- /// <summary>ʹ���շ�������Ĭ��false</summary>
+ /// <summary>使用驼峰命名。默认false</summary>
public Boolean CamelCase { get; set; }
- /// <summary>���Կ�ֵ��Ĭ��false</summary>
+ /// <summary>忽略空值。默认false</summary>
public Boolean IgnoreNullValues { get; set; }
- /// <summary>����ѭ�����á�Ĭ��false</summary>
+ /// <summary>忽略循环引用。默认false</summary>
public Boolean IgnoreCycles { get; set; }
- /// <summary>������ʽ����Ĭ��false</summary>
+ /// <summary>缩进格式化。默认false</summary>
public Boolean WriteIndented { get; set; }
- /// <summary>ʹ������ʱ���ʽ��Ĭ��false</summary>
+ /// <summary>使用完整时间格式。默认false</summary>
public Boolean FullTime { get; set; }
- /// <summary>ö��ʹ���ַ�����Ĭ��falseʹ������</summary>
+ /// <summary>枚举使用字符串。默认false使用数字</summary>
public Boolean EnumString { get; set; }
- /// <summary>��������Ϊ�ַ���������JS���ȶ�ʧ��Ĭ��false</summary>
+ /// <summary>长整型作为字符串。避免JS精度丢失,默认false</summary>
public Boolean Int64AsString { get; set; }
}
```
-**ʾ��**��
+**示例**:
```csharp
var options = new JsonOptions
{
@@ -184,15 +184,15 @@ var options = new JsonOptions
var json = obj.ToJson(options);
```
-### Format - ��ʽ�� JSON
+### Format - 格式化 JSON
```csharp
public static String Format(String json)
```
-��ѹ���� JSON �ַ�����ʽ��Ϊ����ʽ��
+将压缩的 JSON 字符串格式化为易读格式。
-**ʾ��**��
+**示例**:
```csharp
var json = """{"id":1,"name":"test","items":[1,2,3]}""";
var formatted = JsonHelper.Format(json);
@@ -207,9 +207,9 @@ var formatted = JsonHelper.Format(json);
// }
```
-## IJsonHost �ӿ�
+## IJsonHost 接口
-`IJsonHost` �� JSON ���л��ĺ��Ľӿڣ������л���ͬ��ʵ�֣�
+`IJsonHost` 是 JSON 序列化的核心接口,可以切换不同的实现:
```csharp
public interface IJsonHost
@@ -226,22 +226,22 @@ public interface IJsonHost
}
```
-### �л�ʵ��
+### 切换实现
```csharp
-// Ĭ��ʹ�� FastJson
+// 默认使用 FastJson
JsonHelper.Default = new FastJson();
-// ��� System.Text.Json��.NET 5+��
+// 切换到 System.Text.Json(.NET 5+)
JsonHelper.Default = new SystemJson();
```
-## ʹ�ó���
+## 使用场景
-### 1. Web API ���ݽ���
+### 1. Web API 数据交换
```csharp
-// ���л���Ӧ
+// 序列化响应
public class ApiResult<T>
{
public Int32 Code { get; set; }
@@ -256,40 +256,40 @@ var result = new ApiResult<User>
Data = new User { Id = 1, Name = "test" }
};
-// ʹ���շ�������ǰ���Ѻã�
+// 使用驼峰命名(前端友好)
var json = result.ToJson(false, true, true);
-// ������Ӧ
+// 解析响应
var response = json.ToJsonEntity<ApiResult<User>>();
```
-### 2. ���������
+### 2. 配置文件处理
```csharp
-// ��ȡ JSON ����
+// 读取 JSON 配置
var json = File.ReadAllText("config.json");
var config = json.ToJsonEntity<AppConfig>();
-// ��������
-var newJson = config.ToJson(true); // ��ʽ�������Ķ�
+// 保存配置
+var newJson = config.ToJson(true); // 格式化便于阅读
File.WriteAllText("config.json", newJson);
```
-### 3. ��־��¼
+### 3. 日志记录
```csharp
public void LogRequest(Object request)
{
- // ���л��������������־
+ // 序列化请求参数用于日志
var json = request.ToJson();
XTrace.WriteLine($"Request: {json}");
}
```
-### 4. ��̬���ݴ���
+### 4. 动态数据处理
```csharp
-// ������ȷ���ṹ�� JSON
+// 处理不确定结构的 JSON
var json = await httpClient.GetStringAsync(url);
var dict = json.DecodeJson();
@@ -299,70 +299,70 @@ if (dict.TryGetValue("error", out var error))
}
var data = dict["data"] as IDictionary<String, Object>;
-// ��̬�����ֶ�...
+// 动态访问字段...
```
-### 5. ���������;�������
+### 5. 处理长整型精度问题
```csharp
-// JavaScript ����ȷ��ʾ���� 2^53 ������
+// JavaScript 无法精确表示超过 2^53 的整数
var options = new JsonOptions { Int64AsString = true };
var obj = new { Id = 9007199254740993L };
var json = obj.ToJson(options);
-// {"Id":"9007199254740993"} // �ַ�����ʽ�����⾫�ȶ�ʧ
+// {"Id":"9007199254740993"} // 字符串形式,避免精度丢失
```
-## �������ʹ���
+## 特殊类型处理
-### ����ʱ��
+### 日期时间
```csharp
var obj = new { Time = DateTime.Now };
-// Ĭ�ϸ�ʽ
+// 默认格式
obj.ToJson();
// {"Time":"2025-01-07 12:00:00"}
-// ���� ISO ��ʽ
+// 完整 ISO 格式
var options = new JsonOptions { FullTime = true };
obj.ToJson(options);
// {"Time":"2025-01-07T12:00:00.0000000+08:00"}
```
-### ö��
+### 枚举
```csharp
public enum Status { Pending, Active, Closed }
var obj = new { Status = Status.Active };
-// Ĭ��ʹ������
+// 默认使用数字
obj.ToJson();
// {"Status":1}
-// ʹ���ַ���
+// 使用字符串
var options = new JsonOptions { EnumString = true };
obj.ToJson(options);
// {"Status":"Active"}
```
-### �ֽ�����
+### 字节数组
```csharp
var obj = new { Data = new Byte[] { 1, 2, 3, 4 } };
-// Ĭ�� Base64
+// 默认 Base64
obj.ToJson();
// {"Data":"AQIDBA=="}
```
-## ���ʵ��
+## 最佳实践
-### 1. �������ö���
+### 1. 复用配置对象
```csharp
-// ����ȫ������
+// 定义全局配置
public static class JsonConfig
{
public static readonly JsonOptions Api = new()
@@ -378,41 +378,41 @@ public static class JsonConfig
};
}
-// ʹ��
+// 使用
var json = data.ToJson(JsonConfig.Api);
```
-### 2. ������ֵ
+### 2. 处理空值
```csharp
-// �����л�ʱע���ֵ
+// 反序列化时注意空值
var user = json.ToJsonEntity<User>();
if (user == null)
{
- // JSON Ϊ null �����ʧ��
+ // JSON 为 null 或解析失败
}
-// ��ʹ�ÿ��ַ������
+// 或使用空字符串检查
if (json.IsNullOrEmpty()) return;
var user = json.ToJsonEntity<User>();
```
-### 3. ������������
+### 3. 大数据量处理
```csharp
-// ���ڴ������ݣ����Ƿ�������
-// ����һ�������л�/�����л��������
+// 对于大量数据,考虑分批处理
+// 避免一次性序列化/反序列化超大对象
```
-## ����˵��
+## 性能说明
-- `FastJson` ��Գ��������Ż����ʺϴ����Ӧ��
-- ���ڸ�����Ҫ���л��� `System.Text.Json`
-- ����Ƶ������ `JsonOptions`�����鸴��
-- �ַ�������ʹ�ö�����Ż�
+- `FastJson` 针对常见场景优化,适合大多数应用
+- 对于高性能要求,可切换到 `System.Text.Json`
+- 避免频繁创建 `JsonOptions`,建议复用
+- 字符串操作使用对象池优化
-## �������
+## 相关链接
-- [���������л� Binary](binary-���������л�Binary.md)
-- [XML ���л�](xml-XML���л�Xml.md)
-- [����ϵͳ Config](config-����ϵͳConfig.md)
+- [二进制序列化 Binary](binary-二进制序列化Binary.md)
+- [XML 序列化](xml-XML序列化Xml.md)
+- [配置系统 Config](config-配置系统Config.md)
diff --git "a/Doc/Web\351\200\232\347\224\250\344\273\244\347\211\214JwtBuilder.md" "b/Doc/Web\351\200\232\347\224\250\344\273\244\347\211\214JwtBuilder.md"
index 301d20b..0fb49b5 100644
--- "a/Doc/Web\351\200\232\347\224\250\344\273\244\347\211\214JwtBuilder.md"
+++ "b/Doc/Web\351\200\232\347\224\250\344\273\244\347\211\214JwtBuilder.md"
@@ -1,23 +1,23 @@
-# Webͨ������ JwtBuilder
+# Web通用令牌 JwtBuilder
-## ����
+## 概述
-`JwtBuilder` �� NewLife.Core �е� JSON Web Token (JWT) ���ɺ���֤�����ࡣJWT ��һ�ֽ��ա����������Ƹ�ʽ���㷺���� Web API ��֤����Ȩ��JwtBuilder ֧�� HS256/HS384/HS512 �� RS256/RS384/RS512 �������㷨��
+`JwtBuilder` 是 NewLife.Core 中的 JSON Web Token (JWT) 生成和验证工具类。JWT 是一种紧凑、自包含的令牌格式,广泛用于 Web API 认证和授权。JwtBuilder 支持 HS256/HS384/HS512 和 RS256/RS384/RS512 等主流算法。
-**�����ռ�**��`NewLife.Web`
-**�ĵ���ַ**��https://newlifex.com/core/jwt
+**命名空间**:`NewLife.Web`
+**文档地址**:https://newlifex.com/core/jwt
-## ��������
+## 核心特性
-- **���㷨֧��**��HS256��HS384��HS512��RS256��RS384��RS512
-- **������**��֧�� iss��sub��aud��exp��nbf��iat��jti �ȱ�����
-- **�Զ�������**��֧����������Я�������Զ�������
-- **ʱ����֤**���Զ���֤����ʱ�����Чʱ��
-- **����չ**��֧��ע���Զ���ǩ���㷨
+- **多算法支持**:HS256、HS384、HS512、RS256、RS384、RS512
+- **标准声明**:支持 iss、sub、aud、exp、nbf、iat、jti 等标准声明
+- **自定义数据**:支持在令牌中携带任意自定义数据
+- **时间验证**:自动验证过期时间和生效时间
+- **可扩展**:支持注册自定义签名算法
-## ���ٿ�ʼ
+## 快速开始
-### ��������
+### 生成令牌
```csharp
using NewLife.Web;
@@ -25,21 +25,21 @@ using NewLife.Web;
var builder = new JwtBuilder
{
Secret = "your-secret-key-at-least-32-characters",
- Expire = DateTime.Now.AddHours(2), // 2Сʱ�����
- Subject = "user123", // �û���ʶ
- Issuer = "MyApp" // �䷢��
+ Expire = DateTime.Now.AddHours(2), // 2小时后过期
+ Subject = "user123", // 用户标识
+ Issuer = "MyApp" // 颁发者
};
-// �����Զ�������
+// 添加自定义数据
builder["role"] = "admin";
-builder["name"] = "����";
+builder["name"] = "张三";
-// ��������
+// 生成令牌
var token = builder.Encode(new { });
Console.WriteLine(token);
```
-### ��֤����
+### 验证令牌
```csharp
var builder = new JwtBuilder
@@ -49,82 +49,82 @@ var builder = new JwtBuilder
if (builder.TryDecode(token, out var message))
{
- Console.WriteLine($"�û�: {builder.Subject}");
- Console.WriteLine($"��ɫ: {builder["role"]}");
- Console.WriteLine($"����ʱ��: {builder.Expire}");
+ Console.WriteLine($"用户: {builder.Subject}");
+ Console.WriteLine($"角色: {builder["role"]}");
+ Console.WriteLine($"过期时间: {builder.Expire}");
}
else
{
- Console.WriteLine($"��֤ʧ��: {message}");
+ Console.WriteLine($"验证失败: {message}");
}
```
-## API �ο�
+## API 参考
-### ����
+### 属性
-#### ������
+#### 标准声明
```csharp
-/// <summary>�䷢�� (iss)</summary>
+/// <summary>颁发者 (iss)</summary>
public String? Issuer { get; set; }
-/// <summary>���������� (sub)���ɴ���û�ID</summary>
+/// <summary>主体所有人 (sub),可存放用户ID</summary>
public String? Subject { get; set; }
-/// <summary>���� (aud)</summary>
+/// <summary>受众 (aud)</summary>
public String? Audience { get; set; }
-/// <summary>����ʱ�� (exp)��Ĭ��2Сʱ</summary>
+/// <summary>过期时间 (exp),默认2小时</summary>
public DateTime Expire { get; set; }
-/// <summary>��Чʱ�� (nbf)���ڴ�֮ǰ��Ч</summary>
+/// <summary>生效时间 (nbf),在此之前无效</summary>
public DateTime NotBefore { get; set; }
-/// <summary>�䷢ʱ�� (iat)</summary>
+/// <summary>颁发时间 (iat)</summary>
public DateTime IssuedAt { get; set; }
-/// <summary>���Ʊ�ʶ (jti)</summary>
+/// <summary>令牌标识 (jti)</summary>
public String? Id { get; set; }
```
-#### ��������
+#### 配置属性
```csharp
-/// <summary>�㷨��Ĭ��HS256</summary>
+/// <summary>算法,默认HS256</summary>
public String Algorithm { get; set; }
-/// <summary>�������ͣ�Ĭ��JWT</summary>
+/// <summary>令牌类型,默认JWT</summary>
public String? Type { get; set; }
-/// <summary>��Կ</summary>
+/// <summary>密钥</summary>
public String? Secret { get; set; }
-/// <summary>�Զ���������</summary>
+/// <summary>自定义数据项</summary>
public IDictionary<String, Object?> Items { get; }
```
-#### ������
+#### 索引器
```csharp
-// ��ȡ�������Զ�������
+// 获取或设置自定义数据
public Object? this[String key] { get; set; }
```
-### Encode - ��������
+### Encode - 生成令牌
```csharp
public String Encode(Object payload)
```
-�����ݱ���Ϊ JWT �����ַ�����
+将数据编码为 JWT 令牌字符串。
-**����**��
-- `payload`��Ҫ��������ݶ���
+**参数**:
+- `payload`:要编码的数据对象
-**����ֵ**��JWT �����ַ���
+**返回值**:JWT 令牌字符串
-**ʾ��**��
+**示例**:
```csharp
var builder = new JwtBuilder
{
@@ -133,11 +133,11 @@ var builder = new JwtBuilder
Subject = "user_001"
};
-// ��ʽ1��ʹ�����Ժ�������
+// 方式1:使用属性和索引器
builder["permissions"] = new[] { "read", "write" };
var token1 = builder.Encode(new { });
-// ��ʽ2��ֱ�Ӵ������
+// 方式2:直接传入对象
var token2 = builder.Encode(new
{
userId = 123,
@@ -146,27 +146,27 @@ var token2 = builder.Encode(new
});
```
-### TryDecode - ��֤����������
+### TryDecode - 验证并解码令牌
```csharp
public Boolean TryDecode(String token, out String? message)
```
-��֤ JWT ���Ʋ��������ݡ�
+验证 JWT 令牌并解码数据。
-**����**��
-- `token`��JWT �����ַ���
-- `message`����֤ʧ��ʱ�Ĵ�����Ϣ
+**参数**:
+- `token`:JWT 令牌字符串
+- `message`:验证失败时的错误信息
-**����ֵ**����֤�Ƿ�ɹ�
+**返回值**:验证是否成功
-**��֤����**��
-1. JWT ��ʽ�Ƿ���ȷ������ʽ��
-2. ǩ���Ƿ���Ч
-3. �Ƿ�����Ч����
-4. �Ƿ�����Ч
+**验证内容**:
+1. JWT 格式是否正确(三段式)
+2. 签名是否有效
+3. 是否在有效期内
+4. 是否已生效
-**ʾ��**��
+**示例**:
```csharp
var builder = new JwtBuilder
{
@@ -175,51 +175,51 @@ var builder = new JwtBuilder
if (builder.TryDecode(token, out var message))
{
- // ��֤�ɹ�����ȡ����
+ // 验证成功,读取数据
var userId = builder.Subject;
var expire = builder.Expire;
var permissions = builder["permissions"];
}
else
{
- // ��֤ʧ��
- Console.WriteLine($"����: {message}");
- // ���ܵĴ���:
- // - "JWT��ʽ����ȷ"
- // - "�����ѹ���"
- // - "����δ��Ч"
- // - "δ������Կ"
+ // 验证失败
+ Console.WriteLine($"错误: {message}");
+ // 可能的错误:
+ // - "JWT格式不正确"
+ // - "令牌已过期"
+ // - "令牌未生效"
+ // - "未设置密钥"
}
```
-### Parse - ����������֤
+### Parse - 仅解析不验证
```csharp
public String[]? Parse(String token)
```
-���������ƽṹ������֤ǩ����������Ҫ����֤ǰ��ȡ���ݵij�����
+仅解析令牌结构,不验证签名。用于需要在验证前读取内容的场景。
-**����ֵ**������ʽ���� [header, payload, signature]����ʽ���� null
+**返回值**:三段式数组 [header, payload, signature],格式错误返回 null
-**ʾ��**��
+**示例**:
```csharp
var builder = new JwtBuilder();
var parts = builder.Parse(token);
if (parts != null)
{
- // ���Զ�ȡ�㷨������ʱ���
- Console.WriteLine($"�㷨: {builder.Algorithm}");
- Console.WriteLine($"����: {builder.Expire}");
+ // 可以读取算法、过期时间等
+ Console.WriteLine($"算法: {builder.Algorithm}");
+ Console.WriteLine($"过期: {builder.Expire}");
- // Ȼ��������Կ����������֤
+ // 然后设置密钥进行完整验证
builder.Secret = "...";
if (builder.TryDecode(token, out _)) { }
}
```
-### RegisterAlgorithm - ע���Զ����㷨
+### RegisterAlgorithm - 注册自定义算法
```csharp
public static void RegisterAlgorithm(
@@ -228,18 +228,18 @@ public static void RegisterAlgorithm(
JwtDecodeDelegate? decode)
```
-ע���Զ���ǩ���㷨��
+注册自定义签名算法。
-**ʾ��**��
+**示例**:
```csharp
-// ע���Զ����㷨
+// 注册自定义算法
JwtBuilder.RegisterAlgorithm(
"ES256",
(data, secret) => ECDsaHelper.SignSha256(data, secret),
(data, secret, signature) => ECDsaHelper.VerifySha256(data, secret, signature)
);
-// ʹ���Զ����㷨
+// 使用自定义算法
var builder = new JwtBuilder
{
Algorithm = "ES256",
@@ -248,23 +248,23 @@ var builder = new JwtBuilder
var token = builder.Encode(new { });
```
-## ֧�ֵ��㷨
+## 支持的算法
-| �㷨 | ���� | ��ԿҪ�� | ˵�� |
+| 算法 | 类型 | 密钥要求 | 说明 |
|------|------|---------|------|
-| HS256 | HMAC | �Գ���Կ | Ĭ���㷨���ʺϴ�������� |
-| HS384 | HMAC | �Գ���Կ | �����Ĺ�ϣ |
-| HS512 | HMAC | �Գ���Կ | ��Ĺ�ϣ |
-| RS256 | RSA | ��˽Կ�� | �ǶԳƼ��ܣ��ʺϷֲ�ʽ |
-| RS384 | RSA | ��˽Կ�� | �����Ĺ�ϣ |
-| RS512 | RSA | ��˽Կ�� | ��Ĺ�ϣ |
+| HS256 | HMAC | 对称密钥 | 默认算法,适合大多数场景 |
+| HS384 | HMAC | 对称密钥 | 更长的哈希 |
+| HS512 | HMAC | 对称密钥 | 最长的哈希 |
+| RS256 | RSA | 公私钥对 | 非对称加密,适合分布式 |
+| RS384 | RSA | 公私钥对 | 更长的哈希 |
+| RS512 | RSA | 公私钥对 | 最长的哈希 |
-## ʹ�ó���
+## 使用场景
-### 1. API ��֤
+### 1. API 认证
```csharp
-// ��¼�ӿ� - ��������
+// 登录接口 - 生成令牌
[HttpPost("login")]
public IActionResult Login(String username, String password)
{
@@ -285,7 +285,7 @@ public IActionResult Login(String username, String password)
return Ok(new { token });
}
-// ��֤�м��
+// 验证中间件
public class JwtMiddleware
{
public async Task InvokeAsync(HttpContext context)
@@ -312,14 +312,14 @@ public class JwtMiddleware
}
```
-### 2. ˢ������
+### 2. 刷新令牌
```csharp
public class TokenService
{
public (String accessToken, String refreshToken) CreateTokenPair(User user)
{
- // �������� - ������Ч
+ // 访问令牌 - 短期有效
var accessBuilder = new JwtBuilder
{
Secret = _secret,
@@ -328,7 +328,7 @@ public class TokenService
};
accessBuilder["type"] = "access";
- // ˢ������ - ������Ч
+ // 刷新令牌 - 长期有效
var refreshBuilder = new JwtBuilder
{
Secret = _secret,
@@ -347,7 +347,7 @@ public class TokenService
if (!builder.TryDecode(refreshToken, out _)) return null;
if (builder["type"]?.ToString() != "refresh") return null;
- // �����µķ�������
+ // 生成新的访问令牌
var newBuilder = new JwtBuilder
{
Secret = _secret,
@@ -361,10 +361,10 @@ public class TokenService
}
```
-### 3. RSA �ǶԳ�ǩ��
+### 3. RSA 非对称签名
```csharp
-// �����ǩ����ʹ��˽Կ��
+// 服务端签名(使用私钥)
var privateKey = File.ReadAllText("private.pem");
var builder = new JwtBuilder
{
@@ -375,7 +375,7 @@ var builder = new JwtBuilder
};
var token = builder.Encode(new { });
-// �ͻ���/����������֤��ʹ�ù�Կ��
+// 客户端/其他服务验证(使用公钥)
var publicKey = File.ReadAllText("public.pem");
var verifier = new JwtBuilder
{
@@ -384,19 +384,19 @@ var verifier = new JwtBuilder
};
if (verifier.TryDecode(token, out var msg))
{
- Console.WriteLine($"��֤�ɹ�: {verifier.Subject}");
+ Console.WriteLine($"验证成功: {verifier.Subject}");
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ��ȫ����Կ����
+### 1. 安全的密钥管理
```csharp
-// ���Ƽ���Ӳ������Կ
+// 不推荐:硬编码密钥
var builder = new JwtBuilder { Secret = "my-secret" };
-// �Ƽ��������û�������ȡ
+// 推荐:从配置或环境变量读取
var builder = new JwtBuilder
{
Secret = Environment.GetEnvironmentVariable("JWT_SECRET")
@@ -404,58 +404,58 @@ var builder = new JwtBuilder
};
```
-### 2. �����Ĺ���ʱ��
+### 2. 合理的过期时间
```csharp
-// �������ƣ����ڣ�15����-2Сʱ��
+// 访问令牌:短期(15分钟-2小时)
Expire = DateTime.Now.AddMinutes(30);
-// ˢ�����ƣ����ڣ�1-7�죩
+// 刷新令牌:中期(1-7天)
Expire = DateTime.Now.AddDays(7);
-// ��ס�����ƣ����ڣ�30�죩
+// 记住我令牌:长期(30天)
Expire = DateTime.Now.AddDays(30);
```
-### 3. ������������
+### 3. 最小化令牌内容
```csharp
-// ���Ƽ�����Ŵ�������
-builder["userProfile"] = new { /* ����� */ };
+// 不推荐:存放大量数据
+builder["userProfile"] = new { /* 大对象 */ };
-// �Ƽ�������ű�Ҫ��ʶ
-builder.Subject = user.Id.ToString(); // ��Ҫ����ʱ�����ݿ�
-builder["role"] = user.Role; // ���õ���Ȩ��Ϣ
+// 推荐:仅存放必要标识
+builder.Subject = user.Id.ToString(); // 需要详情时查数据库
+builder["role"] = user.Role; // 常用的授权信息
```
-### 4. ��֤��������
+### 4. 验证所有声明
```csharp
if (builder.TryDecode(token, out var message))
{
- // ������֤�䷢��
+ // 额外验证颁发者
if (builder.Issuer != "MyApp")
{
- // �䷢�߲�ƥ��
+ // 颁发者不匹配
}
- // ������֤����
+ // 额外验证受众
if (builder.Audience != "web-client")
{
- // ���ڲ�ƥ��
+ // 受众不匹配
}
}
```
-## JWT ��ȫע������
+## JWT 安全注意事项
-1. **��Ҫ�洢��������**��JWT Ĭ�ϲ����ܣ�payload �ɱ� Base64 ����
-2. **ʹ�� HTTPS**����ֹ���Ʊ��м��˽ػ�
-3. **���ú�������ʱ��**���������Ʊ����õķ���
-4. **ʹ���㹻������Կ**��HS256 ���� 32 �ֽ�
-5. **��֤��������**������ iss��aud��exp ��
+1. **不要存储敏感数据**:JWT 默认不加密,payload 可被 Base64 解码
+2. **使用 HTTPS**:防止令牌被中间人截获
+3. **设置合理过期时间**:降低令牌被盗用的风险
+4. **使用足够长的密钥**:HS256 至少 32 字节
+5. **验证所有声明**:包括 iss、aud、exp 等
-## �������
+## 相关链接
-- [�ֲ�ʽ����ǩ������ TokenProvider](token_provider-�ֲ�ʽ����ǩ������TokenProvider.md)
-- [��ȫ��չ SecurityHelper](security_helper-��ȫ��չSecurityHelper.md)
+- [分布式数字签名令牌 TokenProvider](token_provider-分布式数字签名令牌TokenProvider.md)
+- [安全扩展 SecurityHelper](security_helper-安全扩展SecurityHelper.md)
diff --git "a/Doc/XML\345\272\217\345\210\227\345\214\226.md" "b/Doc/XML\345\272\217\345\210\227\345\214\226.md"
index 03734c3..014889b 100644
--- "a/Doc/XML\345\272\217\345\210\227\345\214\226.md"
+++ "b/Doc/XML\345\272\217\345\210\227\345\214\226.md"
@@ -1,23 +1,23 @@
-# XML ���л�
+# XML 序列化
-## ����
+## 概述
-NewLife.Core �ṩ������ XML ���л��ͷ����л����ܣ�ͨ�� `XmlHelper` ��չ�������Է���ؽ��ж����� XML ��ת����֧���Զ�����ע�͡�����ģʽ��������ԣ��ر��ʺ������ļ�������
+NewLife.Core 提供了灵活的 XML 序列化和反序列化功能,通过 `XmlHelper` 扩展方法可以方便地进行对象与 XML 的转换。支持自动添加注释、属性模式输出等特性,特别适合配置文件场景。
-**�����ռ�**��`NewLife.Xml`����չ��������`NewLife.Serialization`������ʵ�֣�
-**�ĵ���ַ**��https://newlifex.com/core/xml
+**命名空间**:`NewLife.Xml`(扩展方法)、`NewLife.Serialization`(核心实现)
+**文档地址**:https://newlifex.com/core/xml
-## ��������
+## 核心特性
-- **��� API**��`ToXml()` �� `ToXmlEntity<T>()` ��չ����
-- **ע��֧��**���Զ����� `Description` �� `DisplayName` ������Ϊע��
-- **����ģʽ**����ѡ���������л�Ϊ XML ���Զ���Ԫ��
-- **�������**��֧��ָ�������ʽ
-- **�ļ�����**��ֱ�����л����ļ�����ļ������л�
+- **简洁 API**:`ToXml()` 和 `ToXmlEntity<T>()` 扩展方法
+- **注释支持**:自动附加 `Description` 和 `DisplayName` 特性作为注释
+- **属性模式**:可选择将属性序列化为 XML 属性而非元素
+- **编码控制**:支持指定编码格式
+- **文件操作**:直接序列化到文件或从文件反序列化
-## ���ٿ�ʼ
+## 快速开始
-### ���л�
+### 序列化
```csharp
using NewLife.Xml;
@@ -36,11 +36,11 @@ var config = new AppConfig
Debug = true
};
-// ���л�Ϊ XML �ַ���
+// 序列化为 XML 字符串
var xml = config.ToXml();
```
-**���**��
+**输出**:
```xml
<?xml version="1.0" encoding="utf-8"?>
<AppConfig>
@@ -50,7 +50,7 @@ var xml = config.ToXml();
</AppConfig>
```
-### �����л�
+### 反序列化
```csharp
using NewLife.Xml;
@@ -68,50 +68,50 @@ var config = xml.ToXmlEntity<AppConfig>();
Console.WriteLine(config.Name); // MyApp
```
-## API �ο�
+## API 参考
-### ToXml - ���л�
+### ToXml - 序列化
```csharp
-// �������л�
+// 基础序列化
public static String ToXml(this Object obj, Encoding? encoding = null,
Boolean attachComment = false, Boolean useAttribute = false)
-// ��������
+// 完整参数
public static String ToXml(this Object obj, Encoding encoding,
Boolean attachComment, Boolean useAttribute, Boolean omitXmlDeclaration)
-// �������
+// 序列化到流
public static void ToXml(this Object obj, Stream stream, Encoding? encoding = null,
Boolean attachComment = false, Boolean useAttribute = false)
-// ���л����ļ�
+// 序列化到文件
public static void ToXmlFile(this Object obj, String file, Encoding? encoding = null,
Boolean attachComment = true)
```
-**����˵��**��
-- `encoding`�������ʽ��Ĭ�� UTF-8
-- `attachComment`���Ƿ�ע�ͣ�ʹ�� Description/DisplayName��
-- `useAttribute`���Ƿ�ʹ�� XML ����ģʽ
-- `omitXmlDeclaration`���Ƿ�ʡ�� XML ����
+**参数说明**:
+- `encoding`:编码格式,默认 UTF-8
+- `attachComment`:是否附加注释(使用 Description/DisplayName)
+- `useAttribute`:是否使用 XML 属性模式
+- `omitXmlDeclaration`:是否省略 XML 声明
-### ToXmlEntity - �����л�
+### ToXmlEntity - 反序列化
```csharp
-// ���ַ��������л�
+// 从字符串反序列化
public static TEntity? ToXmlEntity<TEntity>(this String xml) where TEntity : class
-// ���������л�
+// 从流反序列化
public static TEntity? ToXmlEntity<TEntity>(this Stream stream, Encoding? encoding = null)
-// ���ļ������л�
+// 从文件反序列化
public static TEntity? ToXmlFileEntity<TEntity>(this String file, Encoding? encoding = null)
```
-## ʹ�ó���
+## 使用场景
-### 1. �����ļ�
+### 1. 配置文件
```csharp
using System.ComponentModel;
@@ -119,48 +119,48 @@ using NewLife.Xml;
public class DatabaseConfig
{
- [Description("���ݿ��������ַ")]
+ [Description("数据库服务器地址")]
public String Server { get; set; } = "localhost";
- [Description("���ݿ�˿�")]
+ [Description("数据库端口")]
public Int32 Port { get; set; } = 3306;
- [Description("���ݿ�����")]
+ [Description("数据库名称")]
public String Database { get; set; } = "mydb";
- [Description("�û���")]
+ [Description("用户名")]
public String User { get; set; } = "root";
- [Description("���ӳ�ʱ���룩")]
+ [Description("连接超时(秒)")]
public Int32 Timeout { get; set; } = 30;
}
-// �������ã���ע�ͣ�
+// 保存配置(带注释)
var config = new DatabaseConfig();
config.ToXmlFile("db.config", attachComment: true);
-// ��������
+// 加载配置
var loaded = "db.config".ToXmlFileEntity<DatabaseConfig>();
```
-**���ɵ� XML**��
+**生成的 XML**:
```xml
<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfig>
- <!--���ݿ��������ַ-->
+ <!--数据库服务器地址-->
<Server>localhost</Server>
- <!--���ݿ�˿�-->
+ <!--数据库端口-->
<Port>3306</Port>
- <!--���ݿ�����-->
+ <!--数据库名称-->
<Database>mydb</Database>
- <!--�û���-->
+ <!--用户名-->
<User>root</User>
- <!--���ӳ�ʱ���룩-->
+ <!--连接超时(秒)-->
<Timeout>30</Timeout>
</DatabaseConfig>
```
-### 2. ����ģʽ���
+### 2. 属性模式输出
```csharp
public class Item
@@ -170,18 +170,18 @@ public class Item
public Decimal Price { get; set; }
}
-var item = new Item { Id = 1, Name = "��ƷA", Price = 99.9M };
+var item = new Item { Id = 1, Name = "商品A", Price = 99.9M };
-// Ԫ��ģʽ��Ĭ�ϣ�
+// 元素模式(默认)
var xml1 = item.ToXml();
-// <Item><Id>1</Id><Name>��ƷA</Name><Price>99.9</Price></Item>
+// <Item><Id>1</Id><Name>商品A</Name><Price>99.9</Price></Item>
-// ����ģʽ
+// 属性模式
var xml2 = item.ToXml(useAttribute: true);
-// <Item Id="1" Name="��ƷA" Price="99.9" />
+// <Item Id="1" Name="商品A" Price="99.9" />
```
-### 3. ���Ӷ���
+### 3. 复杂对象
```csharp
public class Order
@@ -209,28 +209,28 @@ var order = new Order
{
Id = 1001,
CreateTime = DateTime.Now,
- Customer = new Customer { Name = "����", Phone = "13800138000" },
+ Customer = new Customer { Name = "张三", Phone = "13800138000" },
Items = new List<OrderItem>
{
- new() { ProductName = "��ƷA", Quantity = 2, Price = 50 },
- new() { ProductName = "��ƷB", Quantity = 1, Price = 100 }
+ new() { ProductName = "商品A", Quantity = 2, Price = 50 },
+ new() { ProductName = "商品B", Quantity = 1, Price = 100 }
}
};
var xml = order.ToXml();
```
-### 4. ʡ�� XML ����
+### 4. 省略 XML 声明
```csharp
-// ʡ�� <?xml version="1.0" encoding="utf-8"?>
+// 省略 <?xml version="1.0" encoding="utf-8"?>
var xml = obj.ToXml(Encoding.UTF8, false, false, true);
```
-### 5. �ֵ����л�
+### 5. 字典序列化
```csharp
-// �ַ����ֵ����ֱ�����л�
+// 字符串字典可以直接序列化
var dict = new Dictionary<String, String>
{
["Key1"] = "Value1",
@@ -240,25 +240,25 @@ var dict = new Dictionary<String, String>
dict.ToXmlFile("settings.xml");
```
-## Xml �ࣨ���÷���
+## Xml 类(高级用法)
-������Ҫ����ϸ���Ƶij���������ֱ��ʹ�� `Xml` �ࣺ
+对于需要更精细控制的场景,可以直接使用 `Xml` 类:
```csharp
using NewLife.Serialization;
-// ���л�
+// 序列化
var xml = new Xml
{
Stream = stream,
Encoding = Encoding.UTF8,
UseAttribute = false,
UseComment = true,
- EnumString = true // ö��ʹ���ַ���
+ EnumString = true // 枚举使用字符串
};
xml.Write(obj);
-// �����л�
+// 反序列化
var xml = new Xml
{
Stream = stream,
@@ -267,28 +267,28 @@ var xml = new Xml
var result = xml.Read(typeof(MyClass));
```
-### Xml ������
+### Xml 类属性
```csharp
public class Xml
{
- /// <summary>ʹ���������</summary>
+ /// <summary>使用特性输出</summary>
public Boolean UseAttribute { get; set; }
- /// <summary>ʹ��ע��</summary>
+ /// <summary>使用注释</summary>
public Boolean UseComment { get; set; }
- /// <summary>ö��ʹ���ַ�����Ĭ��true</summary>
+ /// <summary>枚举使用字符串。默认true</summary>
public Boolean EnumString { get; set; }
- /// <summary>XML�����</summary>
+ /// <summary>XML写入设置</summary>
public XmlWriterSettings Setting { get; set; }
}
```
-## ����֧��
+## 特性支持
-### XmlRoot - ��Ԫ������
+### XmlRoot - 根元素名称
```csharp
[XmlRoot("config")]
@@ -297,10 +297,10 @@ public class AppConfig
public String Name { get; set; }
}
-// ��� <config><Name>...</Name></config>
+// 输出 <config><Name>...</Name></config>
```
-### XmlElement - Ԫ������
+### XmlElement - 元素名称
```csharp
public class User
@@ -310,7 +310,7 @@ public class User
}
```
-### XmlAttribute - �������
+### XmlAttribute - 输出为属性
```csharp
public class Item
@@ -321,10 +321,10 @@ public class Item
public String Name { get; set; }
}
-// ��� <Item Id="1"><Name>...</Name></Item>
+// 输出 <Item Id="1"><Name>...</Name></Item>
```
-### XmlIgnore - �����ֶ�
+### XmlIgnore - 忽略字段
```csharp
public class User
@@ -332,57 +332,57 @@ public class User
public String Name { get; set; }
[XmlIgnore]
- public String Password { get; set; } // �����л�
+ public String Password { get; set; } // 不序列化
}
```
-## ���ʵ��
+## 最佳实践
-### 1. �����ļ�ʹ��ע��
+### 1. 配置文件使用注释
```csharp
-// ����ʱ����ע��
+// 保存时启用注释
config.ToXmlFile("app.config", attachComment: true);
-// ʹ�� Description ��������˵��
-[Description("Ӧ�����ƣ�������־��ʶ")]
+// 使用 Description 特性添加说明
+[Description("应用名称,用于日志标识")]
public String AppName { get; set; }
```
-### 2. �ļ�����ע������
+### 2. 文件操作注意事项
```csharp
-// ToXmlFile ���Զ�����Ŀ¼
+// ToXmlFile 会自动创建目录
config.ToXmlFile("Config/app.xml");
-// ����ļ��Ƿ����
+// 检查文件是否存在
if (File.Exists(file))
{
var config = file.ToXmlFileEntity<AppConfig>();
}
```
-### 3. ����һ����
+### 3. 编码一致性
```csharp
-// ����ͼ���ʹ����ͬ����
+// 保存和加载使用相同编码
var encoding = Encoding.UTF8;
config.ToXmlFile("config.xml", encoding);
var loaded = "config.xml".ToXmlFileEntity<AppConfig>(encoding);
```
-## �� JSON �Ա�
+## 与 JSON 对比
-| ���� | XML | JSON |
+| 特性 | XML | JSON |
|------|-----|------|
-| �ɶ��� | ��ע������ | ������ |
-| ��� | �ϴ� | ��С |
-| ע��֧�� | ԭ��֧�� | ��֧�� |
-| �����ļ� | ? �Ƽ� | ? ���� |
-| API ���� | ? ���Ƽ� | ? �Ƽ� |
+| 可读性 | 带注释更清晰 | 更紧凑 |
+| 体积 | 较大 | 较小 |
+| 注释支持 | 原生支持 | 不支持 |
+| 配置文件 | ? 推荐 | ? 适用 |
+| API 数据 | ? 不推荐 | ? 推荐 |
-## �������
+## 相关链接
-- [JSON ���л�](json-JSON���л�.md)
-- [����ϵͳ Config](config-����ϵͳConfig.md)
-- [���������л� Binary](binary-���������л�Binary.md)
+- [JSON 序列化](json-JSON序列化.md)
+- [配置系统 Config](config-配置系统Config.md)
+- [二进制序列化 Binary](binary-二进制序列化Binary.md)
diff --git "a/Doc/\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226Binary.md" "b/Doc/\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226Binary.md"
index 11f8867..c13cc11 100644
--- "a/Doc/\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226Binary.md"
+++ "b/Doc/\344\272\214\350\277\233\345\210\266\345\272\217\345\210\227\345\214\226Binary.md"
@@ -1,24 +1,24 @@
-# ���������л� Binary
+# 二进制序列化 Binary
-## ����
+## 概述
-`Binary` �� NewLife.Core �еĸ����ܶ��������л��������ڽ��������л�Ϊ���յĶ����Ƹ�ʽ��Ӷ��������ݷ����л�Ϊ�����ر��ʺ�����ͨ�š�Э����������ݴ洢�ȶ����ܺ�����нϸ�Ҫ��ij�����
+`Binary` 是 NewLife.Core 中的高性能二进制序列化器,用于将对象序列化为紧凑的二进制格式或从二进制数据反序列化为对象。特别适合网络通信、协议解析、数据存储等对性能和体积有较高要求的场景。
-**�����ռ�**��`NewLife.Serialization`
-**�ĵ���ַ**��https://newlifex.com/core/binary
+**命名空间**:`NewLife.Serialization`
+**文档地址**:https://newlifex.com/core/binary
-## ��������
+## 核心特性
-- **������**��ֱ�Ӳ����ֽ��������м��ʽת��
-- **���ո�ʽ**��֧��7λ�䳤���������������������
-- **�ֽ������**��֧�ִ��/С���ֽ���
-- **Э��֧��**��֧�� `FieldSize` ���Զ����ֶδ�С
-- **�汾����**��֧��Э��汾����
-- **��չ��ǿ**���������Զ��崦����
+- **高性能**:直接操作字节流,无中间格式转换
+- **紧凑格式**:支持7位变长编码整数,减少数据体积
+- **字节序控制**:支持大端/小端字节序
+- **协议支持**:支持 `FieldSize` 特性定义字段大小
+- **版本兼容**:支持协议版本控制
+- **扩展性强**:可添加自定义处理器
-## ���ٿ�ʼ
+## 快速开始
-### ���л�
+### 序列化
```csharp
using NewLife.Serialization;
@@ -30,122 +30,122 @@ public class User
public Int32 Age { get; set; }
}
-var user = new User { Id = 1, Name = "����", Age = 25 };
+var user = new User { Id = 1, Name = "张三", Age = 25 };
-// �������л�
+// 快速序列化
var packet = Binary.FastWrite(user);
var bytes = packet.ToArray();
-// ��ʹ����
+// 或使用流
using var ms = new MemoryStream();
Binary.FastWrite(user, ms);
```
-### �����л�
+### 反序列化
```csharp
using NewLife.Serialization;
-var bytes = /* ���������� */;
+var bytes = /* 二进制数据 */;
-// ���ٷ����л�
+// 快速反序列化
using var ms = new MemoryStream(bytes);
var user = Binary.FastRead<User>(ms);
```
-## API �ο�
+## API 参考
-### Binary ��
+### Binary 类
-#### ����
+#### 属性
```csharp
-/// <summary>ʹ��7λ����������Ĭ��false��ʹ��</summary>
+/// <summary>使用7位编码整数。默认false不使用</summary>
public Boolean EncodeInt { get; set; }
-/// <summary>С���ֽ���Ĭ��false���</summary>
+/// <summary>小端字节序。默认false大端</summary>
public Boolean IsLittleEndian { get; set; }
-/// <summary>ʹ��ָ����С��FieldSizeAttribute���ԡ�Ĭ��false</summary>
+/// <summary>使用指定大小的FieldSizeAttribute特性。默认false</summary>
public Boolean UseFieldSize { get; set; }
-/// <summary>��С���ȡ���ѡ0/1/2/4��Ĭ��0��ʾѹ����������</summary>
+/// <summary>大小宽度。可选0/1/2/4,默认0表示压缩编码整数</summary>
public Int32 SizeWidth { get; set; }
-/// <summary>�����ַ���ʱ���Ƿ������ͷ��0�ֽڡ�Ĭ��false</summary>
+/// <summary>解析字符串时,是否清空两头的0字节。默认false</summary>
public Boolean TrimZero { get; set; }
-/// <summary>Э��汾������֧�ֶ�汾Э�����л�</summary>
+/// <summary>协议版本。用于支持多版本协议序列化</summary>
public String? Version { get; set; }
-/// <summary>ʹ��������ʱ���ʽ��������ʽʹ��8���ֽڱ����������Ĭ��false</summary>
+/// <summary>使用完整的时间格式。完整格式使用8个字节保存毫秒数,默认false</summary>
public Boolean FullTime { get; set; }
-/// <summary>�ܵ��ֽ�������ȡ��д��</summary>
+/// <summary>总的字节数。读取或写入</summary>
public Int64 Total { get; set; }
```
-#### FastWrite - �������л�
+#### FastWrite - 快速序列化
```csharp
-// ���л�Ϊ���ݰ�
+// 序列化为数据包
public static IPacket FastWrite(Object value, Boolean encodeInt = true)
-// �������
+// 序列化到流
public static Int64 FastWrite(Object value, Stream stream, Boolean encodeInt = true)
```
-**����**��
-- `value`��Ҫ���л��Ķ���
-- `encodeInt`���Ƿ�ʹ��7λ�䳤��������
-- `stream`��Ŀ����
+**参数**:
+- `value`:要序列化的对象
+- `encodeInt`:是否使用7位变长编码整数
+- `stream`:目标流
-**ʾ��**��
+**示例**:
```csharp
-// ���� IPacket
+// 返回 IPacket
var packet = Binary.FastWrite(obj);
var bytes = packet.ToArray();
-// ���
+// 写入流
using var ms = new MemoryStream();
var length = Binary.FastWrite(obj, ms);
```
-#### FastRead - ���ٷ����л�
+#### FastRead - 快速反序列化
```csharp
public static T? FastRead<T>(Stream stream, Boolean encodeInt = true)
```
-**ʾ��**��
+**示例**:
```csharp
using var ms = new MemoryStream(bytes);
var obj = Binary.FastRead<MyClass>(ms);
```
-### �����÷�
+### 完整用法
```csharp
-// ���������
+// 创建序列化器
var bn = new Binary
{
- EncodeInt = true, // ʹ��7λ����
- IsLittleEndian = true, // С���ֽ���
- UseFieldSize = true // ���� FieldSize ����
+ EncodeInt = true, // 使用7位编码
+ IsLittleEndian = true, // 小端字节序
+ UseFieldSize = true // 启用 FieldSize 特性
};
-// ������
+// 设置流
bn.Stream = new MemoryStream();
-// �����
+// 写入数据
bn.Write(obj);
-// ��ȡ���
+// 获取结果
var bytes = bn.GetBytes();
```
```csharp
-// �����л�
+// 反序列化
var bn = new Binary
{
Stream = new MemoryStream(bytes),
@@ -155,22 +155,22 @@ var bn = new Binary
var obj = bn.Read<MyClass>();
```
-## IAccessor �ӿ�
+## IAccessor 接口
-������Ҫ�Զ������л��������ͣ�����ʵ�� `IAccessor` �ӿڣ�
+对于需要自定义序列化逻辑的类型,可以实现 `IAccessor` 接口:
```csharp
public interface IAccessor
{
- /// <summary>����������ȡ</summary>
+ /// <summary>从数据流读取</summary>
Boolean Read(Stream stream, Object context);
- /// <summary>�������</summary>
+ /// <summary>写入数据流</summary>
Boolean Write(Stream stream, Object context);
}
```
-**ʾ��**��
+**示例**:
```csharp
public class CustomPacket : IAccessor
{
@@ -205,29 +205,29 @@ public class CustomPacket : IAccessor
}
```
-## FieldSize ����
+## FieldSize 特性
-`FieldSizeAttribute` ����ָ���ֶεĹ̶���С����������ֶΣ�
+`FieldSizeAttribute` 用于指定字段的固定大小或关联长度字段:
```csharp
public class Protocol
{
public Byte Header { get; set; }
- [FieldSize(2)] // �̶�2�ֽ�
+ [FieldSize(2)] // 固定2字节
public Int16 Length { get; set; }
- [FieldSize("Length")] // ��С�� Length �ֶξ���
+ [FieldSize("Length")] // 大小由 Length 字段决定
public Byte[] Body { get; set; }
- [FieldSize(4)] // �̶�4�ֽ��ַ���
+ [FieldSize(4)] // 固定4字节字符串
public String Code { get; set; }
}
```
-## ʹ�ó���
+## 使用场景
-### 1. ���������
+### 1. 网络协议解析
```csharp
public class TcpMessage
@@ -243,18 +243,18 @@ public class TcpMessage
public Byte End { get; set; } = 0x7E;
}
-// ����
+// 解析
var bn = new Binary(stream) { IsLittleEndian = false, UseFieldSize = true };
var msg = bn.Read<TcpMessage>();
-// ����
+// 构建
var msg = new TcpMessage { MessageId = 0x0001, Body = data };
msg.BodyLength = (UInt16)data.Length;
msg.Checksum = CalculateChecksum(msg);
var packet = Binary.FastWrite(msg);
```
-### 2. JT/T808 ��
+### 2. JT/T808 协议
```csharp
public class JT808Message
@@ -262,22 +262,22 @@ public class JT808Message
public UInt16 MsgId { get; set; }
public UInt16 MsgAttr { get; set; }
- [FieldSize(6)] // 2011��6�ֽڣ�2019��10�ֽ�
+ [FieldSize(6)] // 2011版6字节,2019版10字节
public String Phone { get; set; }
public UInt16 SeqNo { get; set; }
public Byte[] Body { get; set; }
}
-// 2011�汾
+// 2011版本
var bn = new Binary { UseFieldSize = true, Version = "2011" };
var msg = bn.Read<JT808Message>();
-// 2019�汾
+// 2019版本
var bn = new Binary { UseFieldSize = true, Version = "2019" };
```
-### 3. ���ݴ洢
+### 3. 数据存储
```csharp
public class Record
@@ -287,14 +287,14 @@ public class Record
public Byte[] Data { get; set; }
}
-// ���浽�ļ�
+// 保存到文件
using var fs = File.Create("data.bin");
foreach (var record in records)
{
Binary.FastWrite(record, fs);
}
-// �������
+// 从文件加载
using var fs = File.OpenRead("data.bin");
var list = new List<Record>();
while (fs.Position < fs.Length)
@@ -304,10 +304,10 @@ while (fs.Position < fs.Length)
}
```
-### 4. ���������л�
+### 4. 高性能序列化
```csharp
-// ���� Binary ʵ������Ƶ������
+// 复用 Binary 实例避免频繁创建
var bn = new Binary { EncodeInt = true };
foreach (var item in items)
@@ -315,46 +315,46 @@ foreach (var item in items)
bn.Stream = new MemoryStream();
bn.Write(item);
var bytes = bn.GetBytes();
- // ���� bytes...
+ // 处理 bytes...
}
```
-## 7λ�䳤����
+## 7位变长编码
-`EncodeInt = true` ʱ������ʹ��7λ�䳤���룬����������С��ֵ�Ĵ洢�ռ䣺
+`EncodeInt = true` 时,整数使用7位变长编码,可显著减少小数值的存储空间:
-| ֵ��Χ | �ֽ��� |
+| 值范围 | 字节数 |
|--------|--------|
-| 0 ~ 127 | 1 �ֽ� |
-| 128 ~ 16383 | 2 �ֽ� |
-| 16384 ~ 2097151 | 3 �ֽ� |
-| 2097152 ~ 268435455 | 4 �ֽ� |
-| ���� | 5 �ֽ� |
+| 0 ~ 127 | 1 字节 |
+| 128 ~ 16383 | 2 字节 |
+| 16384 ~ 2097151 | 3 字节 |
+| 2097152 ~ 268435455 | 4 字节 |
+| 更大 | 5 字节 |
```csharp
-// ���ñ䳤����
+// 启用变长编码
var bn = new Binary { EncodeInt = true };
bn.Stream = new MemoryStream();
-bn.Write(100); // 1�ֽ�
-bn.Write(1000); // 2�ֽ�
-bn.Write(100000); // 3�ֽ�
+bn.Write(100); // 1字节
+bn.Write(1000); // 2字节
+bn.Write(100000); // 3字节
```
-## �ֽ���
+## 字节序
```csharp
-// ����ֽ��������ֽ���Ĭ�ϣ�
+// 大端字节序(网络字节序,默认)
var bn = new Binary { IsLittleEndian = false };
-bn.Write((Int32)0x12345678); // ���: 12 34 56 78
+bn.Write((Int32)0x12345678); // 输出: 12 34 56 78
-// С���ֽ���Intel x86��
+// 小端字节序(Intel x86)
var bn = new Binary { IsLittleEndian = true };
-bn.Write((Int32)0x12345678); // ���: 78 56 34 12
+bn.Write((Int32)0x12345678); // 输出: 78 56 34 12
```
-## ���ʵ��
+## 最佳实践
-### 1. Э�����ͳһ����
+### 1. 协议解析统一配置
```csharp
public static class BinaryConfig
@@ -375,7 +375,7 @@ public static class BinaryConfig
}
```
-### 2. ������
+### 2. 错误处理
```csharp
var bn = new Binary(stream);
@@ -385,32 +385,32 @@ try
}
catch (EndOfStreamException)
{
- // ���ݲ�����
+ // 数据不完整
}
```
-### 3. ���ʣ������
+### 3. 检查剩余数据
```csharp
var bn = new Binary(stream);
-// ����Ƿ����㹻����
-if (bn.CheckRemain(10)) // ������Ҫ10�ֽ�
+// 检查是否有足够数据
+if (bn.CheckRemain(10)) // 至少需要10字节
{
var data = bn.ReadBytes(10);
}
```
-## ���ܶԱ�
+## 性能对比
-| ���л���ʽ | ��� | �ٶ� | ���ó��� |
+| 序列化方式 | 体积 | 速度 | 适用场景 |
|-----------|------|------|---------|
-| Binary | ��С | ��� | Э�顢�洢 |
-| JSON | �е� | �е� | API������ |
-| XML | ��� | ���� | ���á��ĵ� |
+| Binary | 最小 | 最快 | 协议、存储 |
+| JSON | 中等 | 中等 | API、配置 |
+| XML | 最大 | 较慢 | 配置、文档 |
-## �������
+## 相关链接
-- [JSON ���л�](json-JSON���л�.md)
-- [XML ���л�](xml-XML���л�.md)
-- [���ݰ� IPacket](packet-���ݰ�IPacket.md)
+- [JSON 序列化](json-JSON序列化.md)
+- [XML 序列化](xml-XML序列化.md)
+- [数据包 IPacket](packet-数据包IPacket.md)
diff --git "a/Doc/\345\217\215\345\260\204\346\211\251\345\261\225Reflect.md" "b/Doc/\345\217\215\345\260\204\346\211\251\345\261\225Reflect.md"
index ca2aa4e..2cfe8d6 100644
--- "a/Doc/\345\217\215\345\260\204\346\211\251\345\261\225Reflect.md"
+++ "b/Doc/\345\217\215\345\260\204\346\211\251\345\261\225Reflect.md"
@@ -1,45 +1,45 @@
-# ������չ Reflect
+# 反射扩展 Reflect
-## ����
+## 概述
-`Reflect` �� NewLife.Core �еĸ����ܷ��乤���࣬�ṩ���ͻ�ȡ���������á����Զ�д�������ȹ��ܡ�֧��˽�г�Ա���ʡ����Դ�Сдƥ�䣬��ͨ�� `IReflect` �ӿ�֧�ֿ��滻�ķ���ʵ�֡�
+`Reflect` 是 NewLife.Core 中的高性能反射工具类,提供类型获取、方法调用、属性读写、对象拷贝等功能。支持私有成员访问、忽略大小写匹配,并通过 `IReflect` 接口支持可替换的反射实现。
-**�����ռ�**��`NewLife.Reflection`
-**�ĵ���ַ**��https://newlifex.com/core/reflect
+**命名空间**:`NewLife.Reflection`
+**文档地址**:https://newlifex.com/core/reflect
-## ��������
+## 核心特性
-- **������**��Ĭ��ʵ�ֻ��ڻ��棬֧���л�Ϊ Emit ������ʵ��
-- **������**�����з���������չ������ʽ�ṩ
-- **������**��֧��˽�г�Ա����̬��Ա���̳г�Ա�ķ���
-- **�����**��֧�ֺ��Դ�Сд�ij�Աƥ��
-- **����չ**��ͨ�� `IReflect` �ӿ�֧���Զ���ʵ��
+- **高性能**:默认实现基于缓存,支持切换为 Emit 高性能实现
+- **易用性**:所有方法都以扩展方法形式提供
+- **完整性**:支持私有成员、静态成员、继承成员的访问
+- **灵活性**:支持忽略大小写的成员匹配
+- **可扩展**:通过 `IReflect` 接口支持自定义实现
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife.Reflection;
-// ����ʵ��
+// 创建实例
var obj = typeof(MyClass).CreateInstance();
-// ���÷���
+// 调用方法
obj.Invoke("DoWork", "param1", 123);
-// ��ȡ����
+// 读取属性
var value = obj.GetValue("Name");
-// ��������
+// 设置属性
obj.SetValue("Name", "NewValue");
-// ����
+// 对象拷贝
var target = new MyClass();
target.Copy(source);
```
-## API �ο�
+## API 参考
-### ���ͻ�ȡ
+### 类型获取
#### GetTypeEx
@@ -47,21 +47,21 @@ target.Copy(source);
public static Type? GetTypeEx(this String typeName)
```
-�����������ƻ�ȡ���ͣ���������ǰĿ¼ DLL ���Զ����ء�
+根据类型名称获取类型,可搜索当前目录 DLL 并自动加载。
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡϵͳ����
+// 获取系统类型
var type1 = "System.String".GetTypeEx();
-// ��ȡ�������ռ������
+// 获取带命名空间的类型
var type2 = "MyApp.Models.User".GetTypeEx();
-// ��ȡ������������
+// 获取程序集限定名类型
var type3 = "MyApp.Models.User, MyApp".GetTypeEx();
```
-### ��Ա��ȡ
+### 成员获取
#### GetMethodEx
@@ -69,14 +69,14 @@ var type3 = "MyApp.Models.User, MyApp".GetTypeEx();
public static MethodInfo? GetMethodEx(this Type type, String name, params Type[] paramTypes)
```
-��ȡ������֧�ֲ�������ƥ�䡣
+获取方法,支持参数类型匹配。
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡ�η���
+// 获取无参方法
var method1 = typeof(MyClass).GetMethodEx("DoWork");
-// ��ȡ���η���
+// 获取带参方法
var method2 = typeof(MyClass).GetMethodEx("DoWork", typeof(String), typeof(Int32));
```
@@ -86,14 +86,14 @@ var method2 = typeof(MyClass).GetMethodEx("DoWork", typeof(String), typeof(Int32
public static MethodInfo[] GetMethodsEx(this Type type, String name, Int32 paramCount = -1)
```
-��ȡָ�����Ƶķ������ϣ�֧�ְ������������ˡ�
+获取指定名称的方法集合,支持按参数个数过滤。
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡ������Ϊ DoWork �ķ���
+// 获取所有名为 DoWork 的方法
var methods1 = typeof(MyClass).GetMethodsEx("DoWork");
-// ��ȡ��������Ϊ 2 �� DoWork ����
+// 获取参数个数为 2 的 DoWork 方法
var methods2 = typeof(MyClass).GetMethodsEx("DoWork", 2);
```
@@ -103,17 +103,17 @@ var methods2 = typeof(MyClass).GetMethodsEx("DoWork", 2);
public static PropertyInfo? GetPropertyEx(this Type type, String name, Boolean ignoreCase = false)
```
-��ȡ���ԣ�����˽�С���̬�������Ա��
+获取属性,搜索私有、静态、基类成员。
-**ʾ��**��
+**示例**:
```csharp
-// ��ȷƥ��
+// 精确匹配
var prop1 = typeof(MyClass).GetPropertyEx("Name");
-// ���Դ�Сд
+// 忽略大小写
var prop2 = typeof(MyClass).GetPropertyEx("name", true);
-// ��ȡ˽������
+// 获取私有属性
var prop3 = typeof(MyClass).GetPropertyEx("_internalValue");
```
@@ -123,9 +123,9 @@ var prop3 = typeof(MyClass).GetPropertyEx("_internalValue");
public static FieldInfo? GetFieldEx(this Type type, String name, Boolean ignoreCase = false)
```
-��ȡ�ֶΣ�����˽�С���̬�������Ա��
+获取字段,搜索私有、静态、基类成员。
-**ʾ��**��
+**示例**:
```csharp
var field = typeof(MyClass).GetFieldEx("_count");
```
@@ -136,9 +136,9 @@ var field = typeof(MyClass).GetFieldEx("_count");
public static MemberInfo? GetMemberEx(this Type type, String name, Boolean ignoreCase = false)
```
-��ȡ��Ա�����Ի��ֶΣ������ȷ������ԡ�
+获取成员(属性或字段),优先返回属性。
-**ʾ��**��
+**示例**:
```csharp
var member = typeof(MyClass).GetMemberEx("Name", true);
```
@@ -150,21 +150,21 @@ public static IList<FieldInfo> GetFields(this Type type, Boolean baseFirst)
public static IList<PropertyInfo> GetProperties(this Type type, Boolean baseFirst)
```
-��ȡ�������л����ֶ�/�����б���
+获取用于序列化的字段/属性列表。
-**����˵��**��
-- `baseFirst`���Ƿ�����Ա��������
+**参数说明**:
+- `baseFirst`:是否基类成员优先排序
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡ���п����л����ԣ���������
+// 获取所有可序列化属性,基类优先
var props = typeof(MyClass).GetProperties(baseFirst: true);
-// ��ȡ���п����л��ֶ�
+// 获取所有可序列化字段
var fields = typeof(MyClass).GetFields(baseFirst: false);
```
-### ʵ�������뷽������
+### 实例创建与方法调用
#### CreateInstance
@@ -172,14 +172,14 @@ var fields = typeof(MyClass).GetFields(baseFirst: false);
public static Object? CreateInstance(this Type type, params Object?[] parameters)
```
-���䴴��ָ�����͵�ʵ����
+反射创建指定类型的实例。
-**ʾ��**��
+**示例**:
```csharp
-// �����ι��캯��
+// 调用无参构造函数
var obj1 = typeof(MyClass).CreateInstance();
-// ���ô��ι��캯��
+// 调用带参构造函数
var obj2 = typeof(MyClass).CreateInstance("name", 123);
```
@@ -190,19 +190,19 @@ public static Object? Invoke(this Object target, String name, params Object?[] p
public static Object? Invoke(this Object? target, MethodBase method, params Object?[]? parameters)
```
-������÷�����
+反射调用方法。
-**ʾ��**��
+**示例**:
```csharp
var obj = new MyClass();
-// ����ʵ������
+// 调用实例方法
var result = obj.Invoke("Calculate", 10, 20);
-// ���þ�̬������target Ϊ���ͣ�
+// 调用静态方法(target 为类型)
var result2 = typeof(MyClass).Invoke("StaticMethod", "param");
-// ����˽�з���
+// 调用私有方法
var result3 = obj.Invoke("PrivateMethod");
```
@@ -212,17 +212,17 @@ var result3 = obj.Invoke("PrivateMethod");
public static Boolean TryInvoke(this Object target, String name, out Object? value, params Object?[] parameters)
```
-���Ե��÷�����������ʱ���� false �����׳��쳣��
+尝试调用方法,不存在时返回 false 而不抛出异常。
-**ʾ��**��
+**示例**:
```csharp
if (obj.TryInvoke("MaybeExists", out var result, "param"))
{
- Console.WriteLine($"���: {result}");
+ Console.WriteLine($"结果: {result}");
}
else
{
- Console.WriteLine("����������");
+ Console.WriteLine("方法不存在");
}
```
@@ -232,9 +232,9 @@ else
public static Object? InvokeWithParams(this Object? target, MethodBase method, IDictionary? parameters)
```
-ʹ���ֵ�������÷������ʺϲ�����ƥ�䳡����
+使用字典参数调用方法,适合参数名匹配场景。
-**ʾ��**��
+**示例**:
```csharp
var parameters = new Dictionary<String, Object>
{
@@ -244,7 +244,7 @@ var parameters = new Dictionary<String, Object>
var result = obj.InvokeWithParams(method, parameters);
```
-### ���Զ�д
+### 属性读写
#### GetValue
@@ -253,19 +253,19 @@ public static Object? GetValue(this Object target, String name, Boolean throwOnE
public static Object? GetValue(this Object? target, MemberInfo member)
```
-��ȡ����/�ֶ�ֵ��
+获取属性/字段值。
-**ʾ��**��
+**示例**:
```csharp
var obj = new MyClass { Name = "test" };
-// �����ƻ�ȡ
+// 按名称获取
var name = obj.GetValue("Name");
-// ������ʱ���� null �������쳣
+// 不存在时返回 null 而不抛异常
var value = obj.GetValue("NotExists", throwOnError: false);
-// ����Ա��ȡ
+// 按成员获取
var prop = typeof(MyClass).GetPropertyEx("Name");
var name2 = obj.GetValue(prop);
```
@@ -277,27 +277,27 @@ public static Boolean SetValue(this Object target, String name, Object? value)
public static void SetValue(this Object target, MemberInfo member, Object? value)
```
-��������/�ֶ�ֵ��
+设置属性/字段值。
-**ʾ��**��
+**示例**:
```csharp
var obj = new MyClass();
-// ����������
+// 按名称设置
obj.SetValue("Name", "newValue");
-// ����Ա����
+// 按成员设置
var prop = typeof(MyClass).GetPropertyEx("Name");
obj.SetValue(prop, "anotherValue");
-// ����Ƿ����óɹ�
+// 检查是否设置成功
if (obj.SetValue("MaybeExists", "value"))
{
- Console.WriteLine("���óɹ�");
+ Console.WriteLine("设置成功");
}
```
-### ����
+### 对象拷贝
#### Copy
@@ -306,36 +306,36 @@ public static void Copy(this Object target, Object src, Boolean deep = false, pa
public static void Copy(this Object target, IDictionary<String, Object?> dic, Boolean deep = false)
```
-��Դ������ֵ俽�����ݵ�Ŀ�����
+从源对象或字典拷贝数据到目标对象。
-**����˵��**��
-- `deep`���Ƿ���ȿ���������ֵ�������ã�
-- `excludes`��Ҫ�ų��ij�Ա����
+**参数说明**:
+- `deep`:是否深度拷贝(复制值而非引用)
+- `excludes`:要排除的成员名称
-**ʾ��**��
+**示例**:
```csharp
-var source = new User { Name = "����", Age = 25 };
+var source = new User { Name = "张三", Age = 25 };
var target = new UserDto();
-// dz����
+// 浅拷贝
target.Copy(source);
-// ���
+// 深拷贝
target.Copy(source, deep: true);
-// �ų�ijЩ�ֶ�
+// 排除某些字段
target.Copy(source, excludes: "Password", "Secret");
-// ���ֵ俽��
+// 从字典拷贝
var dic = new Dictionary<String, Object?>
{
- ["Name"] = "����",
+ ["Name"] = "李四",
["Age"] = 30
};
target.Copy(dic);
```
-### ������
+### 类型辅助
#### GetElementTypeEx
@@ -343,9 +343,9 @@ target.Copy(dic);
public static Type? GetElementTypeEx(this Type type)
```
-��ȡ���͵�Ԫ�����ͣ����ϡ�����ȣ���
+获取类型的元素类型(集合、数组等)。
-**ʾ��**��
+**示例**:
```csharp
typeof(List<String>).GetElementTypeEx() // typeof(String)
typeof(String[]).GetElementTypeEx() // typeof(String)
@@ -359,15 +359,15 @@ public static Object? ChangeType(this Object? value, Type conversionType)
public static TResult? ChangeType<TResult>(this Object? value)
```
-����ת����
+类型转换。
-**ʾ��**��
+**示例**:
```csharp
-// ����ת��
+// 泛型转换
var num = "123".ChangeType<Int32>(); // 123
var date = "2024-01-15".ChangeType<DateTime>();
-// �Ƿ���ת��
+// 非泛型转换
var value = "true".ChangeType(typeof(Boolean));
```
@@ -377,18 +377,18 @@ var value = "true".ChangeType(typeof(Boolean));
public static String GetName(this Type type, Boolean isfull = false)
```
-��ȡ���͵��Ѻ����ơ�
+获取类型的友好名称。
-**ʾ��**��
+**示例**:
```csharp
typeof(List<String>).GetName() // "List<String>"
typeof(List<String>).GetName(true) // "System.Collections.Generic.List<System.String>"
typeof(Dictionary<String, Int32>).GetName() // "Dictionary<String, Int32>"
```
-## ʹ�ó���
+## 使用场景
-### 1. ORM ʵ��ӳ��
+### 1. ORM 实体映射
```csharp
public class EntityMapper
@@ -413,7 +413,7 @@ public class EntityMapper
}
```
-### 2. ���ð�
+### 2. 配置绑定
```csharp
public class ConfigBinder
@@ -435,7 +435,7 @@ public class ConfigBinder
}
```
-### 3. ���ϵͳ
+### 3. 插件系统
```csharp
public class PluginLoader
@@ -452,13 +452,13 @@ public class PluginLoader
{
if (plugin.TryInvoke(action, out var result, args))
{
- Console.WriteLine($"ִ�гɹ�: {result}");
+ Console.WriteLine($"执行成功: {result}");
}
}
}
```
-### 4. DTO ת��
+### 4. DTO 转换
```csharp
public static class DtoExtensions
@@ -476,23 +476,23 @@ public static class DtoExtensions
}
}
-// ʹ��
+// 使用
var dto = user.ToDto<UserDto>();
user.UpdateFrom(dto, "Id", "CreateTime");
```
-## ���ʵ��
+## 最佳实践
-### 1. ʹ�� TryInvoke �����쳣
+### 1. 使用 TryInvoke 避免异常
```csharp
-// ? �Ƽ���ʹ�� TryInvoke
+// ? 推荐:使用 TryInvoke
if (obj.TryInvoke("Method", out var result))
{
- // �������
+ // 处理结果
}
-// ? ���Ƽ����������쳣
+// ? 不推荐:可能抛异常
try
{
var result = obj.Invoke("Method");
@@ -500,43 +500,43 @@ try
catch (XException) { }
```
-### 2. ���淴��Ԫ����
+### 2. 缓存反射元数据
```csharp
-// ? �Ƽ������� PropertyInfo
+// ? 推荐:缓存 PropertyInfo
private static readonly PropertyInfo _nameProp = typeof(User).GetPropertyEx("Name");
public String GetName(User user) => user.GetValue(_nameProp) as String;
-// ? ���Ƽ���ÿ�ζ�����
+// ? 不推荐:每次都查找
public String GetName(User user) => user.GetValue("Name") as String;
```
-### 3. ʹ�ú��Դ�Сдƥ��
+### 3. 使用忽略大小写匹配
```csharp
-// ���� JSON �����л��ȳ���
+// 处理 JSON 反序列化等场景
var value = obj.GetValue("username", throwOnError: false);
if (value == null)
{
- // ���Ժ��Դ�Сд
+ // 尝试忽略大小写
var member = obj.GetType().GetMemberEx("username", ignoreCase: true);
if (member != null) value = obj.GetValue(member);
}
```
-## ����˵��
+## 性能说明
-- Ĭ�� `DefaultReflect` ʵ��ʹ�û��棬�ʺϴ��������
-- ��Ƶ���䳡�����л�Ϊ `EmitReflect` ʵ�֣�
+- 默认 `DefaultReflect` 实现使用缓存,适合大多数场景
+- 高频反射场景可切换为 `EmitReflect` 实现:
```csharp
Reflect.Provider = new EmitReflect();
```
-- `GetProperties` �� `GetFields` ����ᱻ����
-- ��Ա����ʹ���ֵ仺�棬�״η��ʺ����ܽӽ�ֱ�ӵ���
+- `GetProperties` 和 `GetFields` 结果会被缓存
+- 成员查找使用字典缓存,首次访问后性能接近直接调用
-## �������
+## 相关链接
-- [����ʱ��Ϣ Runtime](runtime-����ʱ��ϢRuntime.md)
-- [�ű����� ScriptEngine](script_engine-�ű�����ScriptEngine.md)
-- [�������� ObjectContainer](object_container-��������ObjectContainer.md)
+- [运行时信息 Runtime](runtime-运行时信息Runtime.md)
+- [脚本引擎 ScriptEngine](script_engine-脚本引擎ScriptEngine.md)
+- [对象容器 ObjectContainer](object_container-对象容器ObjectContainer.md)
diff --git "a/Doc/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225StringHelper.md" "b/Doc/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225StringHelper.md"
index 249e5fe..2b46cc5 100644
--- "a/Doc/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225StringHelper.md"
+++ "b/Doc/\345\255\227\347\254\246\344\270\262\346\211\251\345\261\225StringHelper.md"
@@ -1,42 +1,42 @@
-# �ַ�����չ StringHelper
+# 字符串扩展 StringHelper
-## ����
+## 概述
-`StringHelper` �� NewLife.Core �е��ַ������������࣬�ṩ�˷ḻ���ַ�����չ�����������Ƚϡ���ȡ����֡�ƴ�ӡ��༭���������ȹ��ܣ���������ճ������е��ַ���������
+`StringHelper` 是 NewLife.Core 中的字符串处理工具类,提供了丰富的字符串扩展方法,包括比较、截取、拆分、拼接、编辑距离搜索等功能,极大简化了日常开发中的字符串操作。
-**�����ռ�**��`NewLife`
-**�ĵ���ַ**��https://newlifex.com/core/string_helper
+**命名空间**:`NewLife`
+**文档地址**:https://newlifex.com/core/string_helper
-## ��������
+## 核心特性
-- **��ֵ��ȫ**�����з���������ȷ���� null �Ϳ��ַ���
-- **���Դ�Сд**���ṩ���ֺ��Դ�Сд�ıȽϷ���
-- **��Чʵ��**��ʹ�� `StringBuilder` �ػ���`Span<T>` �ȼ����Ż�����
-- **ģ��ƥ��**������ Levenshtein �༭����� LCS ������������㷨
+- **空值安全**:所有方法都能正确处理 null 和空字符串
+- **忽略大小写**:提供多种忽略大小写的比较方法
+- **高效实现**:使用 `StringBuilder` 池化、`Span<T>` 等技术优化性能
+- **模糊匹配**:内置 Levenshtein 编辑距离和 LCS 最长公共子序列算法
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife;
-// ��ֵ�ж�
+// 空值判断
var isEmpty = "".IsNullOrEmpty(); // true
var isBlank = " ".IsNullOrWhiteSpace(); // true
-// ���Դ�Сд�Ƚ�
+// 忽略大小写比较
var equal = "Hello".EqualIgnoreCase("hello"); // true
-// �ַ������
+// 字符串拆分
var arr = "1,2,3".SplitAsInt(); // [1, 2, 3]
var dic = "a=1;b=2".SplitAsDictionary(); // {a:1, b:2}
-// �ַ���ƴ��
+// 字符串拼接
var str = new[] { 1, 2, 3 }.Join(","); // "1,2,3"
```
-## API �ο�
+## API 参考
-### ��ֵ�ж�
+### 空值判断
#### IsNullOrEmpty
@@ -44,14 +44,14 @@ var str = new[] { 1, 2, 3 }.Join(","); // "1,2,3"
public static Boolean IsNullOrEmpty(this String? value)
```
-�ж��ַ����Ƿ�Ϊ null ����ַ�����
+判断字符串是否为 null 或空字符串。
-**ʾ��**��
+**示例**:
```csharp
String? s1 = null;
s1.IsNullOrEmpty() // true
"".IsNullOrEmpty() // true
-" ".IsNullOrEmpty() // false���ո���գ�
+" ".IsNullOrEmpty() // false(空格不算空)
"hello".IsNullOrEmpty() // false
```
@@ -61,9 +61,9 @@ s1.IsNullOrEmpty() // true
public static Boolean IsNullOrWhiteSpace(this String? value)
```
-�ж��ַ����Ƿ�Ϊ null�����ַ�����������հ��ַ���
+判断字符串是否为 null、空字符串或仅包含空白字符。
-**ʾ��**��
+**示例**:
```csharp
String? s1 = null;
s1.IsNullOrWhiteSpace() // true
@@ -73,7 +73,7 @@ s1.IsNullOrWhiteSpace() // true
"hello".IsNullOrWhiteSpace() // false
```
-### �ַ����Ƚ�
+### 字符串比较
#### EqualIgnoreCase
@@ -81,9 +81,9 @@ s1.IsNullOrWhiteSpace() // true
public static Boolean EqualIgnoreCase(this String? value, params String?[] strs)
```
-���Դ�Сд�Ƚ��ַ����Ƿ�������һ����ѡ�ַ�����ȡ�
+忽略大小写比较字符串是否与任意一个候选字符串相等。
-**ʾ��**��
+**示例**:
```csharp
"Hello".EqualIgnoreCase("hello") // true
"Hello".EqualIgnoreCase("HELLO", "World") // true
@@ -96,9 +96,9 @@ public static Boolean EqualIgnoreCase(this String? value, params String?[] strs)
public static Boolean StartsWithIgnoreCase(this String? value, params String?[] strs)
```
-���Դ�Сд�ж��ַ����Ƿ�������һ����ѡǰ��ʼ��
+忽略大小写判断字符串是否以任意一个候选前缀开始。
-**ʾ��**��
+**示例**:
```csharp
"HelloWorld".StartsWithIgnoreCase("hello") // true
"HelloWorld".StartsWithIgnoreCase("HELLO", "Hi") // true
@@ -110,15 +110,15 @@ public static Boolean StartsWithIgnoreCase(this String? value, params String?[]
public static Boolean EndsWithIgnoreCase(this String? value, params String?[] strs)
```
-���Դ�Сд�ж��ַ����Ƿ�������һ����ѡ��������
+忽略大小写判断字符串是否以任意一个候选后缀结束。
-**ʾ��**��
+**示例**:
```csharp
"HelloWorld".EndsWithIgnoreCase("world") // true
"HelloWorld".EndsWithIgnoreCase("WORLD", "Test") // true
```
-### ͨ���ƥ��
+### 通配符匹配
#### IsMatch
@@ -126,36 +126,36 @@ public static Boolean EndsWithIgnoreCase(this String? value, params String?[] st
public static Boolean IsMatch(this String pattern, String input, StringComparison comparisonType = StringComparison.CurrentCulture)
```
-ʹ��ͨ���ģʽƥ���ַ�����֧�� `*`��ƥ�����ⳤ�ȣ��� `?`��ƥ�䵥���ַ�����
+使用通配符模式匹配字符串,支持 `*`(匹配任意长度)和 `?`(匹配单个字符)。
-**�ص�**��
-- ���������ʽ��������Ч
-- ʱ�临�Ӷ� O(n) ~ O(n*m)
-- ���蹹���������
+**特点**:
+- 比正则表达式更简单、更高效
+- 时间复杂度 O(n) ~ O(n*m)
+- 无需构造正则对象
-**ʾ��**��
+**示例**:
```csharp
"*.txt".IsMatch("document.txt") // true
"*.txt".IsMatch("document.doc") // false
"file?.txt".IsMatch("file1.txt") // true
"file?.txt".IsMatch("file12.txt") // false
-"*".IsMatch("anything") // true��ƥ�����У�
+"*".IsMatch("anything") // true(匹配所有)
"test*end".IsMatch("test123end") // true
```
-### �ַ������
+### 字符串拆分
-#### Split����չ���أ�
+#### Split(扩展重载)
```csharp
public static String[] Split(this String? value, params String[] separators)
```
-��ָ���ָ�������ַ������Զ����˿���Ŀ��
+按指定分隔符拆分字符串,自动过滤空条目。
-**ʾ��**��
+**示例**:
```csharp
-"a,b,,c".Split(",") // ["a", "b", "c"]���Զ����˿��
+"a,b,,c".Split(",") // ["a", "b", "c"](自动过滤空项)
"a;b,c".Split(",", ";") // ["a", "b", "c"]
```
@@ -165,20 +165,20 @@ public static String[] Split(this String? value, params String[] separators)
public static Int32[] SplitAsInt(this String? value, params String[] separators)
```
-����ַ�����ת��Ϊ�������飬Ĭ��ʹ�ö��źͷֺ���Ϊ�ָ�����
+拆分字符串并转换为整数数组,默认使用逗号和分号作为分隔符。
-**�ص�**��
-- �Զ����˿ո�
-- �Զ�������Ч����
-- �����ظ���
+**特点**:
+- 自动过滤空格
+- 自动过滤无效数字
+- 保留重复项
-**ʾ��**��
+**示例**:
```csharp
"1,2,3".SplitAsInt() // [1, 2, 3]
-"1, 2, 3".SplitAsInt() // [1, 2, 3]���Զ�ȥ���ո�
-"1;2;3".SplitAsInt() // [1, 2, 3]��֧�ַֺţ�
-"1,abc,3".SplitAsInt() // [1, 3]���������
-"1,1,2".SplitAsInt() // [1, 1, 2]�������ظ���
+"1, 2, 3".SplitAsInt() // [1, 2, 3](自动去除空格)
+"1;2;3".SplitAsInt() // [1, 2, 3](支持分号)
+"1,abc,3".SplitAsInt() // [1, 3](过滤无效项)
+"1,1,2".SplitAsInt() // [1, 1, 2](保留重复)
```
#### SplitAsDictionary
@@ -191,35 +191,35 @@ public static IDictionary<String, String> SplitAsDictionary(
Boolean trimQuotation = false)
```
-���ַ������Ϊ��ֵ���ֵ䡣
+将字符串拆分为键值对字典。
-**����˵��**��
-- `nameValueSeparator`����ֵ�ָ�����Ĭ�� `=`
-- `separator`����Ŀ�ָ�����Ĭ�� `;`
-- `trimQuotation`���Ƿ�ȥ��ֵ���˵�����
+**参数说明**:
+- `nameValueSeparator`:键值分隔符,默认 `=`
+- `separator`:条目分隔符,默认 `;`
+- `trimQuotation`:是否去除值两端的引号
-**ʾ��**��
+**示例**:
```csharp
-// �����÷�
+// 基本用法
"a=1;b=2".SplitAsDictionary()
// { "a": "1", "b": "2" }
-// �Զ���ָ���
+// 自定义分隔符
"a:1,b:2".SplitAsDictionary(":", ",")
// { "a": "1", "b": "2" }
-// ȥ������
+// 去除引号
"name='test';value=\"123\"".SplitAsDictionary("=", ";", true)
// { "name": "test", "value": "123" }
-// ����ʱʹ�����
+// 无键名时使用序号
"value1;key=value2".SplitAsDictionary()
// { "[0]": "value1", "key": "value2" }
```
-> **��ʾ**�����ص��ֵ䲻���ִ�Сд��`StringComparer.OrdinalIgnoreCase`��
+> **提示**:返回的字典不区分大小写(`StringComparer.OrdinalIgnoreCase`)
-### �ַ���ƴ��
+### 字符串拼接
#### Join
@@ -228,17 +228,17 @@ public static String Join(this IEnumerable value, String separator = ",")
public static String Join<T>(this IEnumerable<T> value, String separator = ",", Func<T, Object?>? func = null)
```
-������Ԫ��ƴ��Ϊ�ַ�����
+将集合元素拼接为字符串。
-**ʾ��**��
+**示例**:
```csharp
-// �����÷�
+// 基本用法
new[] { 1, 2, 3 }.Join() // "1,2,3"
new[] { 1, 2, 3 }.Join(";") // "1;2;3"
-// ʹ��ת������
-var users = new[] { new { Name = "����" }, new { Name = "����" } };
-users.Join(",", u => u.Name) // "����,����"
+// 使用转换函数
+var users = new[] { new { Name = "张三" }, new { Name = "李四" } };
+users.Join(",", u => u.Name) // "张三,李四"
```
#### Separate
@@ -247,9 +247,9 @@ users.Join(",", u => u.Name) // "
public static StringBuilder Separate(this StringBuilder sb, String separator)
```
-�� `StringBuilder` �ӷָ�����������Կ�ͷ����һ�ε��ò��ӣ���
+向 `StringBuilder` 追加分隔符,但会忽略开头(第一次调用不追加)。
-**ʾ��**��
+**示例**:
```csharp
var sb = new StringBuilder();
sb.Separate(",").Append("a"); // "a"
@@ -257,32 +257,32 @@ sb.Separate(",").Append("b"); // "a,b"
sb.Separate(",").Append("c"); // "a,b,c"
```
-### �ַ�����ȡ
+### 字符串截取
-#### Substring����չ���أ�
+#### Substring(扩展重载)
```csharp
public static String Substring(this String str, String? after, String? before = null, Int32 startIndex = 0, Int32[]? positions = null)
```
-���ַ����н�ȡָ�����֮������ݡ�
+从字符串中截取指定标记之间的内容。
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡ���֮�������
+// 截取标记之后的内容
"Hello[World]End".Substring("[") // "World]End"
-// ��ȡ�������֮�������
+// 截取两个标记之间的内容
"Hello[World]End".Substring("[", "]") // "World"
-// ��ȡ���֮ǰ������
+// 截取标记之前的内容
"Hello[World]End".Substring(null, "[") // "Hello"
-// ��ȡƥ��λ��
+// 获取匹配位置
var positions = new Int32[2];
"Hello[World]End".Substring("[", "]", 0, positions);
-// positions[0] = 6��������ʼλ�ã�
-// positions[1] = 11�����ݽ���λ�ã�
+// positions[0] = 6(内容起始位置)
+// positions[1] = 11(内容结束位置)
```
#### Cut
@@ -291,13 +291,13 @@ var positions = new Int32[2];
public static String Cut(this String str, Int32 maxLength, String? pad = null)
```
-����Ƚ�ȡ�ַ�������ָ������ַ���
+按最大长度截取字符串,可指定填充字符。
-**ʾ��**��
+**示例**:
```csharp
"HelloWorld".Cut(8) // "HelloWor"
-"HelloWorld".Cut(8, "...") // "Hello..."���ܳ��Ȳ�����8��
-"Hi".Cut(8) // "Hi"�����㳤��ԭ�����أ�
+"HelloWorld".Cut(8, "...") // "Hello..."(总长度不超过8)
+"Hi".Cut(8) // "Hi"(不足长度原样返回)
```
#### TrimStart / TrimEnd
@@ -307,11 +307,11 @@ public static String TrimStart(this String str, params String[] starts)
public static String TrimEnd(this String str, params String[] ends)
```
-���ַ�����ͷ/��β�Ƴ�ָ�������ַ����������ִ�Сд��֧�ֶ��ƥ�䡣
+从字符串开头/结尾移除指定的子字符串,不区分大小写,支持多次匹配。
-**ʾ��**��
+**示例**:
```csharp
-"HelloHelloWorld".TrimStart("Hello") // "World"���Ƴ�����ƥ���ǰ��
+"HelloHelloWorld".TrimStart("Hello") // "World"(移除所有匹配的前缀)
"WorldEndEnd".TrimEnd("End") // "World"
```
@@ -322,9 +322,9 @@ public static String CutStart(this String str, params String[] starts)
public static String CutEnd(this String str, params String[] ends)
```
-�Ƴ�ָ�����ַ�������֮ǰ/֮����������ݡ�
+移除指定子字符串及其之前/之后的所有内容。
-**ʾ��**��
+**示例**:
```csharp
"path/to/file.txt".CutStart("/") // "file.txt"
"path/to/file.txt".CutEnd("/") // "path/to"
@@ -337,12 +337,12 @@ public static String EnsureStart(this String? str, String start)
public static String EnsureEnd(this String? str, String end)
```
-ȷ���ַ�����ָ�����ݿ�ʼ/������
+确保字符串以指定内容开始/结束。
-**ʾ��**��
+**示例**:
```csharp
"world".EnsureStart("Hello") // "Helloworld"
-"Hello".EnsureStart("Hello") // "Hello"���Ѵ��������ӣ�
+"Hello".EnsureStart("Hello") // "Hello"(已存在则不添加)
"/api/users".EnsureEnd("/") // "/api/users/"
"/api/users/".EnsureEnd("/") // "/api/users/"
@@ -354,14 +354,14 @@ public static String EnsureEnd(this String? str, String end)
public static String? TrimInvisible(this String? value)
```
-�Ƴ��ַ����еIJ��ɼ� ASCII �����ַ���0-31 �� 127����
+移除字符串中的不可见 ASCII 控制字符(0-31 和 127)。
-**ʾ��**��
+**示例**:
```csharp
"Hello\x00World\x1F".TrimInvisible() // "HelloWorld"
```
-### ����ת��
+### 编码转换
#### GetBytes
@@ -369,38 +369,38 @@ public static String? TrimInvisible(this String? value)
public static Byte[] GetBytes(this String? value, Encoding? encoding = null)
```
-���ַ���ת��Ϊ�ֽ����飬Ĭ��ʹ�� UTF-8 ���롣
+将字符串转换为字节数组,默认使用 UTF-8 编码。
-**ʾ��**��
+**示例**:
```csharp
-"Hello".GetBytes() // UTF-8 ������ֽ�����
-"Hello".GetBytes(Encoding.ASCII) // ASCII ����
-"���".GetBytes(Encoding.UTF8) // UTF-8 ��������
+"Hello".GetBytes() // UTF-8 编码的字节数组
+"Hello".GetBytes(Encoding.ASCII) // ASCII 编码
+"你好".GetBytes(Encoding.UTF8) // UTF-8 编码中文
```
-### �����
+### 模糊搜索
-#### Levenshtein �༭����
+#### Levenshtein 编辑距离
```csharp
public static Int32 LevenshteinDistance(String str1, String str2)
public static String[] LevenshteinSearch(String key, String[] words)
```
-���������ַ���֮��ı༭���루���롢ɾ�����滻���������ٴ�������
+计算两个字符串之间的编辑距离(插入、删除、替换操作的最少次数)。
-**ʾ��**��
+**示例**:
```csharp
-// ����༭����
+// 计算编辑距离
StringHelper.LevenshteinDistance("kitten", "sitting") // 3
-// �����
+// 模糊搜索
var words = new[] { "apple", "application", "banana", "apply" };
StringHelper.LevenshteinSearch("appl", words)
// ["apple", "application", "apply"]
```
-#### LCS �����������
+#### LCS 最长公共子序列
```csharp
public static Int32 LCSDistance(String word, String[] keys)
@@ -408,78 +408,78 @@ public static String[] LCSSearch(String key, String[] words)
public static IEnumerable<T> LCSSearch<T>(this IEnumerable<T> list, String keys, Func<T, String> keySelector, Int32 count = -1)
```
-��������������е�ģ���������ʺ������������顢�Զ���ȫ�ȳ�����
+基于最长公共子序列的模糊搜索,适合用于搜索建议、自动补全等场景。
-**ʾ��**��
+**示例**:
```csharp
var words = new[] { "HelloWorld", "HelloKitty", "GoodBye" };
StringHelper.LCSSearch("Hello", words)
// ["HelloKitty", "HelloWorld"]
-// ��������
+// 泛型搜索
var users = new[] {
- new { Id = 1, Name = "����" },
- new { Id = 2, Name = "����" },
- new { Id = 3, Name = "����" }
+ new { Id = 1, Name = "张三" },
+ new { Id = 2, Name = "张小三" },
+ new { Id = 3, Name = "李四" }
};
-users.LCSSearch("��", u => u.Name, 2)
-// ��������������
+users.LCSSearch("张", u => u.Name, 2)
+// 返回张三、张小三
```
-#### Match ģ��ƥ��
+#### Match 模糊匹配
```csharp
public static IList<KeyValuePair<T, Double>> Match<T>(this IEnumerable<T> list, String keys, Func<T, String> keySelector)
public static IEnumerable<T> Match<T>(this IEnumerable<T> list, String keys, Func<T, String> keySelector, Int32 count, Double confidence = 0.5)
```
-���������ʺ������ͷ���ģ��ƥ���㷨��
+基于命中率和跳过惩罚的模糊匹配算法。
-**ʾ��**��
+**示例**:
```csharp
var products = new[] { "iPhone 15", "iPhone 15 Pro", "Samsung Galaxy" };
products.Match("iPhone", s => s, 2, 0.3)
// ["iPhone 15", "iPhone 15 Pro"]
```
-### ����ת����
+### 文字转语音
```csharp
public static void Speak(this String value)
public static void SpeakAsync(this String value)
```
-����ϵͳ���������ʶ��ı����� Windows ƽ̨����
+调用系统语音引擎朗读文本(仅 Windows 平台)。
-**ʾ��**��
+**示例**:
```csharp
-"��ã�����".Speak(); // ͬ���ʶ�
-"��ã�����".SpeakAsync(); // �첽�ʶ�
+"你好,世界".Speak(); // 同步朗读
+"你好,世界".SpeakAsync(); // 异步朗读
```
-## ���ʵ��
+## 最佳实践
-### 1. ʹ�ÿ�ֵ��ȫ�ķ���
+### 1. 使用空值安全的方法
```csharp
-// �Ƽ���ʹ����չ����
+// 推荐:使用扩展方法
if (str.IsNullOrEmpty()) return;
-// ���Ƽ�����Ҫ���� null
+// 不推荐:需要处理 null
if (str == null || str.Length == 0) return;
```
-### 2. ���������ַ���
+### 2. 解析配置字符串
```csharp
-// �����ַ�������
+// 连接字符串解析
var connStr = "Server=localhost;Database=test;User=root;Password=123456";
var dic = connStr.SplitAsDictionary();
var server = dic["Server"]; // "localhost"
var database = dic["Database"]; // "test"
```
-### 3. URL ��������
+### 3. URL 参数解析
```csharp
var query = "name=test&age=18&tags=a,b,c";
@@ -488,29 +488,29 @@ var name = dic["name"]; // "test"
var tags = dic["tags"].Split(","); // ["a", "b", "c"]
```
-### 4. ʹ�� StringBuilder ��
+### 4. 使用 StringBuilder 池
```csharp
using NewLife.Collections;
-// �ӳ��л�ȡ StringBuilder
+// 从池中获取 StringBuilder
var sb = Pool.StringBuilder.Get();
sb.Append("Hello");
sb.Separate(",").Append("World");
-// �����ַ������黹����
+// 返回字符串并归还到池
var result = sb.Return(true); // "Hello,World"
```
-## ����˵��
+## 性能说明
-- `IsNullOrEmpty` �� `IsNullOrWhiteSpace` ʹ�������Ż�
-- �ַ�����ֺ�ƴ��ʹ�� `StringBuilder` �أ������ڴ����
-- ͨ���ƥ��ʹ�õ�ָ������㷨�������������ʽ����
-- �༭�����㷨��Զ��ַ����Ż�
+- `IsNullOrEmpty` 和 `IsNullOrWhiteSpace` 使用内联优化
+- 字符串拆分和拼接使用 `StringBuilder` 池,减少内存分配
+- 通配符匹配使用单指针回溯算法,避免正则表达式开销
+- 编辑距离算法针对短字符串优化
-## �������
+## 相关链接
-- [����ת�� Utility](utility-����ת��Utility.md)
-- [������չ IOHelper](io_helper-������չIOHelper.md)
-- [·����չ PathHelper](path_helper-·����չPathHelper.md)
+- [类型转换 Utility](utility-类型转换Utility.md)
+- [数据扩展 IOHelper](io_helper-数据扩展IOHelper.md)
+- [路径扩展 PathHelper](path_helper-路径扩展PathHelper.md)
diff --git "a/Doc/\345\256\211\345\205\250\346\211\251\345\261\225SecurityHelper.md" "b/Doc/\345\256\211\345\205\250\346\211\251\345\261\225SecurityHelper.md"
index 3ce0ea1..b6b9b92 100644
--- "a/Doc/\345\256\211\345\205\250\346\211\251\345\261\225SecurityHelper.md"
+++ "b/Doc/\345\256\211\345\205\250\346\211\251\345\261\225SecurityHelper.md"
@@ -1,45 +1,45 @@
-# ��ȫ��չ SecurityHelper
+# 安全扩展 SecurityHelper
-## ����
+## 概述
-`SecurityHelper` �� NewLife.Core �еİ�ȫ�㷨�����࣬�ṩ���õĹ�ϣ�㷨���ԳƼ��ܡ��ǶԳƼ��ܵȹ��ܵ���չ������֧�� MD5��SHA ϵ�С�CRC��AES��DES��RSA �����������㷨��
+`SecurityHelper` 是 NewLife.Core 中的安全算法工具类,提供常用的哈希算法、对称加密、非对称加密等功能的扩展方法。支持 MD5、SHA 系列、CRC、AES、DES、RSA 等主流加密算法。
-**�����ռ�**��`NewLife`
-**�ĵ���ַ**��https://newlifex.com/core/security_helper
+**命名空间**:`NewLife`
+**文档地址**:https://newlifex.com/core/security_helper
-## ��������
+## 核心特性
-- **��ϣ�㷨**��MD5��SHA1��SHA256��SHA384��SHA512��CRC16��CRC32��Murmur128
-- **�ԳƼ���**��AES��DES��3DES��RC4��SM4
-- **�ǶԳƼ���**��RSA��DSA
-- **������**��ʹ���߳̾�̬���������㷨ʵ���������ظ�����
-- **������**�������㷨������չ������ʽ�ṩ
+- **哈希算法**:MD5、SHA1、SHA256、SHA384、SHA512、CRC16、CRC32、Murmur128
+- **对称加密**:AES、DES、3DES、RC4、SM4
+- **非对称加密**:RSA、DSA
+- **高性能**:使用线程静态变量缓存算法实例,避免重复创建
+- **易用性**:所有算法都以扩展方法形式提供
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife;
-// MD5 ��ϣ
-var hash = "password".MD5(); // 32λʮ�������ַ���
-var hash16 = "password".MD5_16(); // 16λʮ�������ַ���
+// MD5 哈希
+var hash = "password".MD5(); // 32位十六进制字符串
+var hash16 = "password".MD5_16(); // 16位十六进制字符串
-// SHA256 ��ϣ
-var sha = data.SHA256(); // �����ֽ�����
-var shaHex = data.SHA256().ToHex(); // תΪʮ�������ַ���
+// SHA256 哈希
+var sha = data.SHA256(); // 返回字节数组
+var shaHex = data.SHA256().ToHex(); // 转为十六进制字符串
-// AES ����
+// AES 加密
var encrypted = data.Encrypt(Aes.Create(), key);
var decrypted = encrypted.Decrypt(Aes.Create(), key);
-// CRC ��
+// CRC 校验
var crc32 = data.Crc();
var crc16 = data.Crc16();
```
-## API �ο�
+## API 参考
-### ��ϣ�㷨
+### 哈希算法
#### MD5
@@ -50,25 +50,25 @@ public static String MD5_16(this String data, Encoding? encoding = null)
public static Byte[] MD5(this FileInfo file)
```
-���� MD5 ɢ��ֵ��
+计算 MD5 散列值。
-**ʾ��**��
+**示例**:
```csharp
-// �ַ��� MD5��32λ��
+// 字符串 MD5(32位)
"password".MD5() // "5F4DCC3B5AA765D61D8327DEB882CF99"
-// �ַ��� MD5��16λ��ȡ�м�8�ֽڣ�
+// 字符串 MD5(16位,取中间8字节)
"password".MD5_16() // "5AA765D61D8327DE"
-// �ֽ����� MD5
+// 字节数组 MD5
var data = Encoding.UTF8.GetBytes("hello");
-var hash = data.MD5(); // ���� 16 �ֽ�����
+var hash = data.MD5(); // 返回 16 字节数组
-// �ļ� MD5
+// 文件 MD5
var fileHash = "large-file.zip".AsFile().MD5().ToHex();
```
-#### SHA ϵ��
+#### SHA 系列
```csharp
public static Byte[] SHA1(this Byte[] data, Byte[]? key)
@@ -77,37 +77,37 @@ public static Byte[] SHA384(this Byte[] data, Byte[]? key)
public static Byte[] SHA512(this Byte[] data, Byte[]? key)
```
-���� SHA ϵ��ɢ��ֵ����ѡ HMAC ��Կ��
+计算 SHA 系列散列值,可选 HMAC 密钥。
-**ʾ��**��
+**示例**:
```csharp
var data = Encoding.UTF8.GetBytes("hello");
-// ��ͨ��ϣ
-var sha256 = data.SHA256(); // 32 �ֽ�
-var sha512 = data.SHA512(null); // 64 �ֽ�
+// 普通哈希
+var sha256 = data.SHA256(); // 32 字节
+var sha512 = data.SHA512(null); // 64 字节
-// HMAC ��ϣ������Կ��
+// HMAC 哈希(带密钥)
var key = Encoding.UTF8.GetBytes("secret");
var hmac256 = data.SHA256(key);
var hmac512 = data.SHA512(key);
```
-#### CRC ��
+#### CRC 校验
```csharp
public static UInt32 Crc(this Byte[] data)
public static UInt16 Crc16(this Byte[] data)
```
-���� CRC У��ֵ��
+计算 CRC 校验值。
-**ʾ��**��
+**示例**:
```csharp
var data = new Byte[] { 1, 2, 3, 4, 5 };
-var crc32 = data.Crc(); // UInt32 У��ֵ
-var crc16 = data.Crc16(); // UInt16 У��ֵ
+var crc32 = data.Crc(); // UInt32 校验值
+var crc16 = data.Crc16(); // UInt16 校验值
```
#### Murmur128
@@ -116,15 +116,15 @@ var crc16 = data.Crc16(); // UInt16 У
public static Byte[] Murmur128(this Byte[] data, UInt32 seed = 0)
```
-���� Murmur128 �Ǽ��ܹ�ϣ�������ڹ�ϣ���ȳ������ٶȱ� MD5 ��ܶࡣ
+计算 Murmur128 非加密哈希,适用于哈希表等场景,速度比 MD5 快很多。
-**ʾ��**��
+**示例**:
```csharp
-var hash = data.Murmur128(); // Ĭ������
-var hashWithSeed = data.Murmur128(12345); // ָ������
+var hash = data.Murmur128(); // 默认种子
+var hashWithSeed = data.Murmur128(12345); // 指定种子
```
-### �ԳƼ���
+### 对称加密
#### Encrypt / Decrypt
@@ -133,47 +133,47 @@ public static Byte[] Encrypt(this SymmetricAlgorithm sa, Byte[] data, Byte[]? pa
public static Byte[] Decrypt(this SymmetricAlgorithm sa, Byte[] data, Byte[]? pass = null, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
```
-�ԳƼ���/�������ݡ�
+对称加密/解密数据。
-**����˵��**��
-- `pass`�����루���Զ���䵽���ʵ���Կ���ȣ�
-- `mode`������ģʽ��CBC/ECB �ȣ���.NET Ĭ�� CBC��Java Ĭ�� ECB
-- `padding`�����ģʽ��Ĭ�� PKCS7����ͬ Java �� PKCS5��
+**参数说明**:
+- `pass`:密码(会自动填充到合适的密钥长度)
+- `mode`:加密模式(CBC/ECB 等),.NET 默认 CBC,Java 默认 ECB
+- `padding`:填充模式,默认 PKCS7(等同 Java 的 PKCS5)
-**ʾ��**��
+**示例**:
```csharp
var data = Encoding.UTF8.GetBytes("Hello World!");
var key = Encoding.UTF8.GetBytes("my-secret-key-16");
-// AES ���ܣ�CBC ģʽ��
+// AES 加密(CBC 模式)
var encrypted = Aes.Create().Encrypt(data, key);
-// AES ����
+// AES 解密
var decrypted = Aes.Create().Decrypt(encrypted, key);
-// ECB ģʽ���� Java ���ݣ�
+// ECB 模式(与 Java 兼容)
var encryptedEcb = Aes.Create().Encrypt(data, key, CipherMode.ECB);
var decryptedEcb = Aes.Create().Decrypt(encryptedEcb, key, CipherMode.ECB);
-// DES ����
+// DES 加密
var desKey = Encoding.UTF8.GetBytes("12345678");
var desEncrypted = DES.Create().Encrypt(data, desKey);
-// 3DES ����
+// 3DES 加密
var tripleDesKey = Encoding.UTF8.GetBytes("123456789012345678901234");
var tripleDesEncrypted = TripleDES.Create().Encrypt(data, tripleDesKey);
```
-#### ��ʽ����
+#### 流式加密
```csharp
public static SymmetricAlgorithm Encrypt(this SymmetricAlgorithm sa, Stream instream, Stream outstream)
public static SymmetricAlgorithm Decrypt(this SymmetricAlgorithm sa, Stream instream, Stream outstream)
```
-�����������м���/���ܣ��ʺϴ������ļ���
+对数据流进行加密/解密,适合处理大文件。
-**ʾ��**��
+**示例**:
```csharp
using var input = File.OpenRead("large-file.bin");
using var output = File.Create("large-file.enc");
@@ -190,9 +190,9 @@ aes.Encrypt(input, output);
public static Byte[] Transform(this ICryptoTransform transform, Byte[] data)
```
-ʹ�� `ICryptoTransform` ֱ��ת�����ݡ�
+使用 `ICryptoTransform` 直接转换数据。
-**ʾ��**��
+**示例**:
```csharp
var aes = Aes.Create();
aes.Key = key;
@@ -211,87 +211,87 @@ var decrypted = decryptor.Transform(encrypted);
public static Byte[] RC4(this Byte[] data, Byte[] pass)
```
-RC4 ��������ܡ�RC4 ���ܺͽ���ʹ����ͬ�ķ�����
+RC4 流密码加密。RC4 加密和解密使用相同的方法。
-**ʾ��**��
+**示例**:
```csharp
var data = Encoding.UTF8.GetBytes("Hello");
var key = Encoding.UTF8.GetBytes("secret");
-// ����
+// 加密
var encrypted = data.RC4(key);
-// ���ܣ�ͬ���ķ�����
+// 解密(同样的方法)
var decrypted = encrypted.RC4(key);
```
-## ������ȫ��
+## 其他安全类
### RSAHelper
-RSA �ǶԳƼ��ܸ����ࡣ
+RSA 非对称加密辅助类。
```csharp
using NewLife.Security;
-// ������Կ��
+// 生成密钥对
var (publicKey, privateKey) = RSAHelper.GenerateKey(2048);
-// ����
+// 加密
var encrypted = RSAHelper.Encrypt(data, publicKey);
-// ����
+// 解密
var decrypted = RSAHelper.Decrypt(encrypted, privateKey);
-// ǩ��
+// 签名
var signature = RSAHelper.Sign(data, privateKey, "SHA256");
-// ��ǩ
+// 验签
var isValid = RSAHelper.Verify(data, signature, publicKey, "SHA256");
```
### DSAHelper
-DSA ����ǩ�������ࡣ
+DSA 数字签名辅助类。
```csharp
using NewLife.Security;
-// ǩ��
+// 签名
var signature = DSAHelper.Sign(data, privateKey);
-// ��ǩ
+// 验签
var isValid = DSAHelper.Verify(data, signature, publicKey);
```
### Rand
-�������������
+随机数生成器。
```csharp
using NewLife.Security;
-// ��������ֽ�
+// 生成随机字节
var bytes = Rand.NextBytes(16);
-// �����������
+// 生成随机整数
var num = Rand.Next(1, 100);
-// ��������ַ���
-var str = Rand.NextString(16); // �������ֺ���ĸ
-var strWithSpecial = Rand.NextString(16, true); // ���������ַ�
+// 生成随机字符串
+var str = Rand.NextString(16); // 包含数字和字母
+var strWithSpecial = Rand.NextString(16, true); // 包含特殊字符
```
-## ʹ�ó���
+## 使用场景
-### 1. �����ϣ�洢
+### 1. 密码哈希存储
```csharp
public class PasswordHelper
{
public String HashPassword(String password, String salt)
{
- // ʹ�� SHA256 + ��ֵ
+ // 使用 SHA256 + 盐值
var data = Encoding.UTF8.GetBytes(password + salt);
return data.SHA256().ToHex();
}
@@ -303,7 +303,7 @@ public class PasswordHelper
}
```
-### 2. API ǩ����֤
+### 2. API 签名验证
```csharp
public class ApiSignature
@@ -322,7 +322,7 @@ public class ApiSignature
}
```
-### 3. ���ݼ��ܴ���
+### 3. 数据加密传输
```csharp
public class SecureTransport
@@ -331,7 +331,7 @@ public class SecureTransport
public SecureTransport(String password)
{
- // ʹ������������Կ
+ // 使用密码派生密钥
_key = password.MD5().ToHex().GetBytes()[..16];
}
@@ -347,7 +347,7 @@ public class SecureTransport
}
```
-### 4. �ļ�������У��
+### 4. 文件完整性校验
```csharp
public class FileVerifier
@@ -365,55 +365,55 @@ public class FileVerifier
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ѡ����ʵ��㷨
+### 1. 选择合适的算法
```csharp
-// �����ϣ��ʹ�� SHA256 ���ǿ���㷨
+// 密码哈希:使用 SHA256 或更强的算法
var passwordHash = (password + salt).GetBytes().SHA256().ToHex();
-// ���������ԣ�MD5 �㹻����
+// 数据完整性:MD5 足够快速
var checksum = data.MD5().ToHex();
-// �����ܹ�ϣ����ʹ�� Murmur128
+// 高性能哈希表:使用 Murmur128
var hash = data.Murmur128();
```
-### 2. ע�����ģʽ������
+### 2. 注意加密模式兼容性
```csharp
-// �� Java ϵͳ����ʱʹ�� ECB ģʽ
+// 与 Java 系统交互时使用 ECB 模式
var encrypted = Aes.Create().Encrypt(data, key, CipherMode.ECB);
-// ��ȫ��Ҫ���ʱʹ�� CBC ģʽ��Ĭ�ϣ�
+// 安全性要求高时使用 CBC 模式(默认)
var encrypted = Aes.Create().Encrypt(data, key, CipherMode.CBC);
```
-### 3. ��Կ����
+### 3. 密钥管理
```csharp
-// ��ҪӲ������Կ
+// 不要硬编码密钥
var key = Environment.GetEnvironmentVariable("ENCRYPTION_KEY")?.ToHex();
-// ʹ�ð�ȫ�������������Կ
+// 使用安全的随机数生成密钥
var randomKey = Rand.NextBytes(32);
```
-## �㷨�Ա�
+## 算法对比
-| �㷨 | ������� | �ٶ� | ��ȫ�� | ��; |
+| 算法 | 输出长度 | 速度 | 安全性 | 用途 |
|------|---------|------|--------|------|
-| MD5 | 16�ֽ� | �ܿ� | �� | У��͡��ǰ�ȫ��ϣ |
-| SHA1 | 20�ֽ� | �� | �� | ���ݾ�ϵͳ |
-| SHA256 | 32�ֽ� | �� | �� | ͨ�ð�ȫ��ϣ |
-| SHA512 | 64�ֽ� | ���� | �ܸ� | �߰�ȫҪ�� |
-| CRC32 | 4�ֽ� | ���� | �� | ����У�� |
-| Murmur128 | 16�ֽ� | ���� | �� | ��ϣ�� |
-
-## �������
-
-- [����ת�� Utility](utility-����ת��Utility.md)
-- [������չ IOHelper](io_helper-������չIOHelper.md)
-- [Webͨ������ JwtBuilder](jwt-Webͨ������JwtBuilder.md)
-- [�ֲ�ʽ����ǩ������ TokenProvider](token_provider-�ֲ�ʽ����ǩ������TokenProvider.md)
+| MD5 | 16字节 | 很快 | 低 | 校验和、非安全哈希 |
+| SHA1 | 20字节 | 快 | 中 | 兼容旧系统 |
+| SHA256 | 32字节 | 中 | 高 | 通用安全哈希 |
+| SHA512 | 64字节 | 较慢 | 很高 | 高安全要求 |
+| CRC32 | 4字节 | 极快 | 无 | 数据校验 |
+| Murmur128 | 16字节 | 极快 | 无 | 哈希表 |
+
+## 相关链接
+
+- [类型转换 Utility](utility-类型转换Utility.md)
+- [数据扩展 IOHelper](io_helper-数据扩展IOHelper.md)
+- [Web通用令牌 JwtBuilder](jwt-Web通用令牌JwtBuilder.md)
+- [分布式数字签名令牌 TokenProvider](token_provider-分布式数字签名令牌TokenProvider.md)
diff --git "a/Doc/\345\257\271\350\261\241\345\256\271\345\231\250ObjectContainer.md" "b/Doc/\345\257\271\350\261\241\345\256\271\345\231\250ObjectContainer.md"
index ca7dfae..d6bef7c 100644
--- "a/Doc/\345\257\271\350\261\241\345\256\271\345\231\250ObjectContainer.md"
+++ "b/Doc/\345\257\271\350\261\241\345\256\271\345\231\250ObjectContainer.md"
@@ -1,92 +1,92 @@
-# �������� ObjectContainer
+# 对象容器 ObjectContainer
-## ���
+## 简介
-`ObjectContainer` �� NewLife.Core �е�����������������֧������ע�루DI�����ܡ��ṩ��ǿ��� IoC �������ܣ�֧�ֵ�����˲̬���������������ڣ����� `IServiceProvider` �ӿڣ�������Ϊ ASP.NET Core ���� DI �IJ���������
+`ObjectContainer` 是 NewLife.Core 中的轻量级对象容器,支持依赖注入(DI)功能。提供简单而强大的 IoC 容器功能,支持单例、瞬态和作用域生命周期,兼容 `IServiceProvider` 接口,可以作为 ASP.NET Core 内置 DI 的补充或替代。
-**�����ռ�**��`NewLife.Model`
-**�ĵ���ַ**��https://newlifex.com/core/object_container
+**命名空间**:`NewLife.Model`
+**文档地址**:https://newlifex.com/core/object_container
-## ��������
+## 核心特性
-- **������**�����ⲿ���������뾫��
-- **������������**��������Singleton����˲̬��Transient����������Scoped��
-- **���캯��ע��**���Զ��������캯������������ѡ��������Ŀ�ƥ�乹�캯��
-- **����ί��**��֧���Զ���ʵ��������
-- **ȫ������**���ṩ `ObjectContainer.Current` �� `ObjectContainer.Provider` ȫ�ַ���
-- **������**��ʵ�� `IServiceProvider` �ӿڣ���� DI ����������
-- **������֧��**��֧�� `IServiceScope` �� `IServiceScopeFactory`
+- **轻量级**:无外部依赖,代码精简
+- **三种生命周期**:单例(Singleton)、瞬态(Transient)、作用域(Scoped)
+- **构造函数注入**:自动解析构造函数参数,优先选择参数最多的可匹配构造函数
+- **工厂委托**:支持自定义实例创建逻辑
+- **全局容器**:提供 `ObjectContainer.Current` 和 `ObjectContainer.Provider` 全局访问
+- **标准兼容**:实现 `IServiceProvider` 接口,与标准 DI 容器互操作
+- **作用域支持**:支持 `IServiceScope` 和 `IServiceScopeFactory`
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife.Model;
-// ��ȡȫ������
+// 获取全局容器
var ioc = ObjectContainer.Current;
-// ע�����
-ioc.AddSingleton<ILogger, ConsoleLogger>(); // ����
-ioc.AddTransient<IUserService, UserService>(); // ˲̬
-ioc.AddScoped<IDbContext, MyDbContext>(); // ������
+// 注册服务
+ioc.AddSingleton<ILogger, ConsoleLogger>(); // 单例
+ioc.AddTransient<IUserService, UserService>(); // 瞬态
+ioc.AddScoped<IDbContext, MyDbContext>(); // 作用域
-// ���������ṩ��
+// 构建服务提供者
var provider = ioc.BuildServiceProvider();
-// ��������
+// 解析服务
var logger = provider.GetService<ILogger>();
var userService = provider.GetRequiredService<IUserService>();
```
-## ��������
+## 核心类型
-### IObjectContainer �ӿ�
+### IObjectContainer 接口
-���������ĺ��Ľӿڣ������˷���ע��ͽ����Ļ���������
+对象容器的核心接口,定义了服务注册和解析的基本能力。
-| ��Ա | ���� | ˵�� |
+| 成员 | 类型 | 说明 |
|------|------|------|
-| `Services` | `IList<IObject>` | ����ע�Ἧ�� |
-| `Register` | ���� | ע�����ͺ����ƣ��ѱ�� EditorBrowsable.Never�� |
-| `Add` | ���� | ���ӷ���ע�ᣬ�����ظ�����ͬһ������ |
-| `TryAdd` | ���� | �������ӷ���ע�ᣬ�������ظ�����ͬһ������ |
-| `GetService` | ���� | �������͵�ʵ�� |
+| `Services` | `IList<IObject>` | 服务注册集合 |
+| `Register` | 方法 | 注册类型和名称(已标记 EditorBrowsable.Never) |
+| `Add` | 方法 | 添加服务注册,允许重复添加同一个服务 |
+| `TryAdd` | 方法 | 尝试添加服务注册,不允许重复添加同一个服务 |
+| `GetService` | 方法 | 解析类型的实例 |
-### ObjectLifetime ö��
+### ObjectLifetime 枚举
-���������������ڲ��ԡ�
+定义服务的生命周期策略。
-| ֵ | ˵�� |
+| 值 | 说明 |
|------|------|
-| `Singleton` | ��ʵ��������Ӧ�ó�������������ֻ��һ��ʵ�� |
-| `Scoped` | �����ڵ�ʵ����ͬһ�������ڹ���ʵ�� |
-| `Transient` | ÿ��һ��ʵ����ÿ����������ʵ�� |
+| `Singleton` | 单实例,整个应用程序生命周期内只有一个实例 |
+| `Scoped` | 容器内单实例,同一作用域内共享实例 |
+| `Transient` | 每次一个实例,每次请求都创建新实例 |
-### IObject �ӿ�
+### IObject 接口
-����ӳ��ӿڣ�������������͡�ʵ�ֺ��������ڡ�
+对象映射接口,描述服务的类型、实现和生命周期。
-| ��Ա | ���� | ˵�� |
+| 成员 | 类型 | 说明 |
|------|------|------|
-| `ServiceType` | `Type` | �������ͣ��ӿڻ���������� |
-| `ImplementationType` | `Type?` | ʵ�����ͣ�����ʵ�������� |
-| `Lifetime` | `ObjectLifetime` | �������ڣ�����ʵ���Ĵ��������ٲ��� |
+| `ServiceType` | `Type` | 服务类型,接口或抽象类类型 |
+| `ImplementationType` | `Type?` | 实现类型,具体实现类类型 |
+| `Lifetime` | `ObjectLifetime` | 生命周期,控制实例的创建和销毁策略 |
-### ServiceDescriptor ��
+### ServiceDescriptor 类
-������������ʵ�� `IObject` �ӿڣ����������������Ϣ��
+服务描述符,实现 `IObject` 接口,描述服务的完整信息。
-| ���� | ���� | ˵�� |
+| 属性 | 类型 | 说明 |
|------|------|------|
-| `ServiceType` | `Type` | �������ͣ�ͨ���ǽӿڻ������ |
-| `ImplementationType` | `Type?` | ʵ�����ͣ������ʵ���� |
-| `Lifetime` | `ObjectLifetime` | �������� |
-| `Instance` | `Object?` | ����ʵ����������ģʽ��Ч |
-| `Factory` | `Func<IServiceProvider, Object>?` | ���������ڴ�������ʵ����ί�� |
+| `ServiceType` | `Type` | 服务类型,通常是接口或抽象类 |
+| `ImplementationType` | `Type?` | 实现类型,具体的实现类 |
+| `Lifetime` | `ObjectLifetime` | 生命周期 |
+| `Instance` | `Object?` | 服务实例,仅单例模式有效 |
+| `Factory` | `Func<IServiceProvider, Object>?` | 对象工厂,用于创建服务实例的委托 |
-## API �ο�
+## API 参考
-### ȫ�ַ���
+### 全局访问
#### Current
@@ -94,11 +94,11 @@ var userService = provider.GetRequiredService<IUserService>();
public static IObjectContainer Current { get; set; }
```
-ȫ��Ĭ������ʵ����Ӧ������ʱ�Զ�������
+全局默认容器实例,应用启动时自动创建。
-**ʾ��**��
+**示例**:
```csharp
-// ���κεط�����ȫ������
+// 在任何地方访问全局容器
var container = ObjectContainer.Current;
container.AddSingleton<IMyService, MyService>();
```
@@ -109,81 +109,81 @@ container.AddSingleton<IMyService, MyService>();
public static IServiceProvider Provider { get; set; }
```
-ȫ��Ĭ�Ϸ����ṩ�ߣ��� `Current` �����Զ�������
+全局默认服务提供者,由 `Current` 容器自动构建。
-**ʾ��**��
+**示例**:
```csharp
-// ֱ��ͨ��ȫ���ṩ�߽�������
+// 直接通过全局提供者解析服务
var service = ObjectContainer.Provider.GetService<IMyService>();
```
#### SetInnerProvider
```csharp
-// �����ڲ������ṩ�ߣ����� UseXxx �Σ�
+// 设置内部服务提供者(用于 UseXxx 阶段)
public static void SetInnerProvider(IServiceProvider innerServiceProvider)
-// �����ڲ������ṩ�߹��������� AddXxx ���ӳٰ�
+// 设置内部服务提供者工厂(用于 AddXxx 阶段延迟绑定)
public static void SetInnerProvider(Func<IServiceProvider> innerServiceProviderFactory)
```
-������ ASP.NET Core �ȿ�ܵ� DI �������ɣ�ʵ����ʽ���ҡ��� ObjectContainer ���Ҳ�������ʱ�����Զ����ڲ��ṩ���в��ҡ�
+用于与 ASP.NET Core 等框架的 DI 容器集成,实现链式查找。当 ObjectContainer 中找不到服务时,会自动从内部提供者中查找。
-**ʾ��**��
+**示例**:
```csharp
-// �� Startup.Configure ������
+// 在 Startup.Configure 中设置
public void Configure(IApplicationBuilder app)
{
ObjectContainer.SetInnerProvider(app.ApplicationServices);
}
-// ���� Program.cs ��ʹ�ù����ӳٰ�
+// 或在 Program.cs 中使用工厂延迟绑定
ObjectContainer.SetInnerProvider(() => app.Services);
```
-### ����ע��
+### 服务注册
-#### AddSingleton��������
+#### AddSingleton(单例)
```csharp
-// ע������ӳ��
+// 注册类型映射
IObjectContainer AddSingleton<TService, TImplementation>()
IObjectContainer AddSingleton(Type serviceType, Type implementationType)
-// ע��ʵ��
+// 注册实例
IObjectContainer AddSingleton<TService>(TService? instance = null)
IObjectContainer AddSingleton(Type serviceType, Object? instance)
-// ע�Ṥ��
+// 注册工厂
IObjectContainer AddSingleton<TService>(Func<IServiceProvider, TService> factory)
IObjectContainer AddSingleton(Type serviceType, Func<IServiceProvider, Object> factory)
```
-ע�ᵥ����������Ӧ�ó�����������ֻ��һ��ʵ����
+注册单例服务,整个应用程序生命周期只有一个实例。
-**ʾ��**��
+**示例**:
```csharp
var ioc = ObjectContainer.Current;
-// ����ӳ��
+// 类型映射
ioc.AddSingleton<ILogger, FileLogger>();
-// ֱ��ע��ʵ��
+// 直接注册实例
var config = new AppConfig { Debug = true };
ioc.AddSingleton<AppConfig>(config);
-// ����ί�У��ӳٴ�����
+// 工厂委托(延迟创建)
ioc.AddSingleton<IDbConnection>(sp =>
{
var config = sp.GetService<AppConfig>();
return new SqlConnection(config.ConnectionString);
});
-// ע���������ͣ����贫��ʵ�����ڲ��Զ�ʵ������
+// 注册自身类型(无需传入实例,内部自动实例化)
ioc.AddSingleton<MyService>();
```
-#### AddTransient��˲̬��
+#### AddTransient(瞬态)
```csharp
IObjectContainer AddTransient<TService, TImplementation>()
@@ -192,17 +192,17 @@ IObjectContainer AddTransient(Type serviceType, Type implementationType)
IObjectContainer AddTransient(Type serviceType, Func<IServiceProvider, Object> factory)
```
-ע��˲̬����ÿ����������ʵ����
+注册瞬态服务,每次请求都创建新实例。
-**ʾ��**��
+**示例**:
```csharp
-// ÿ�ν�����������ʵ��
+// 每次解析都创建新实例
ioc.AddTransient<IUserService, UserService>();
-// ����ע��
+// 自身注册
ioc.AddTransient<OrderProcessor>();
-// ������
+// 工厂委托
ioc.AddTransient<HttpClient>(sp => new HttpClient
{
BaseAddress = new Uri("https://api.example.com"),
@@ -210,7 +210,7 @@ ioc.AddTransient<HttpClient>(sp => new HttpClient
});
```
-#### AddScoped��������
+#### AddScoped(作用域)
```csharp
IObjectContainer AddScoped<TService, TImplementation>()
@@ -219,14 +219,14 @@ IObjectContainer AddScoped(Type serviceType, Type implementationType)
IObjectContainer AddScoped(Type serviceType, Func<IServiceProvider, Object> factory)
```
-ע�����������ͬһ�������ڹ���ʵ����
+注册作用域服务,同一作用域内共享实例。
-**ʾ��**��
+**示例**:
```csharp
-// ͬһ��������
+// 同一作用域共享
ioc.AddScoped<IDbContext, AppDbContext>();
-// ������
+// 工厂委托
ioc.AddScoped<IUnitOfWork>(sp =>
{
var context = sp.GetService<IDbContext>();
@@ -234,37 +234,37 @@ ioc.AddScoped<IUnitOfWork>(sp =>
});
```
-#### TryAdd ϵ��
+#### TryAdd 系列
```csharp
-// ����
+// 单例
IObjectContainer TryAddSingleton<TService, TImplementation>()
IObjectContainer TryAddSingleton<TService>(TService? instance = null)
-// ������
+// 作用域
IObjectContainer TryAddScoped<TService, TImplementation>()
IObjectContainer TryAddScoped<TService>(TService? instance = null)
-// ˲̬
+// 瞬态
IObjectContainer TryAddTransient<TService, TImplementation>()
IObjectContainer TryAddTransient<TService>(TService? instance = null)
```
-�������ӷ�������Ѵ�����ͬ�������������ӣ����� `false`��
+尝试添加服务,如果已存在相同服务类型则不添加,返回 `false`。
-**ʾ��**��
+**示例**:
```csharp
-// ����δע��ʱ����
+// 仅在未注册时添加
ioc.TryAddSingleton<ILogger, ConsoleLogger>();
-// �ڶ������Ӳ�����Ч
-ioc.TryAddSingleton<ILogger, FileLogger>(); // ������
+// 第二次添加不会生效
+ioc.TryAddSingleton<ILogger, FileLogger>(); // 被忽略
-// �� Add ������ӣ����ע������ȣ�
-ioc.AddSingleton<ILogger, FileLogger>(); // ������
+// 用 Add 则会添加(最后注册的优先)
+ioc.AddSingleton<ILogger, FileLogger>(); // 会添加
```
-### ����
+### 服务构建
#### BuildServiceProvider
@@ -273,17 +273,17 @@ public static IServiceProvider BuildServiceProvider(this IObjectContainer contai
public static IServiceProvider BuildServiceProvider(this IObjectContainer container, IServiceProvider? innerServiceProvider)
```
-�Ӷ����������������ṩ�ߡ�
+从对象容器创建服务提供者。
-**ʾ��**��
+**示例**:
```csharp
var ioc = ObjectContainer.Current;
ioc.AddSingleton<IMyService, MyService>();
-// ��������
+// 基本构建
var provider = ioc.BuildServiceProvider();
-// ���ڲ��ṩ�ߣ���ʽ���ң�
+// 带内部提供者(链式查找)
var provider2 = ioc.BuildServiceProvider(existingProvider);
```
@@ -294,9 +294,9 @@ public static IHost BuildHost(this IObjectContainer container)
public static IHost BuildHost(this IObjectContainer container, IServiceProvider? innerServiceProvider)
```
-�Ӷ�����������Ӧ��������
+从对象容器创建应用主机。
-**ʾ��**��
+**示例**:
```csharp
var ioc = ObjectContainer.Current;
ioc.AddSingleton<IMyService, MyService>();
@@ -305,62 +305,62 @@ var host = ioc.BuildHost();
host.Run();
```
-### �������
+### 服务解析
-#### GetService������������
+#### GetService(基本解析)
```csharp
-// IServiceProvider �ӿڷ���
+// IServiceProvider 接口方法
Object? GetService(Type serviceType)
-// ������չ����
+// 泛型扩展方法
T? GetService<T>(this IServiceProvider provider)
T? GetService<T>(this IObjectContainer container)
```
-��ȡ����ʵ����δ�ҵ�ʱ���� null������ʱ���Ȳ������ע��ķ���
+获取服务实例,未找到时返回 null。解析时优先查找最后注册的服务。
-**ʾ��**��
+**示例**:
```csharp
var service = provider.GetService(typeof(IMyService));
var typedService = provider.GetService<IMyService>();
-// ֱ�Ӵ�������ȡ
+// 直接从容器获取
var containerService = ioc.GetService<IMyService>();
```
-#### GetRequiredService����Ҫ������
+#### GetRequiredService(必要解析)
```csharp
Object GetRequiredService(this IServiceProvider provider, Type serviceType)
T GetRequiredService<T>(this IServiceProvider provider)
```
-��ȡ��Ҫ�ķ���δ�ҵ�ʱ�׳� `InvalidOperationException` �쳣��
+获取必要的服务,未找到时抛出 `InvalidOperationException` 异常。
-**ʾ��**��
+**示例**:
```csharp
-// ���δע����׳��쳣
+// 如果未注册会抛出异常
var config = provider.GetRequiredService<AppConfig>();
```
-#### GetServices������������
+#### GetServices(批量解析)
```csharp
IEnumerable<Object> GetServices(this IServiceProvider provider, Type serviceType)
IEnumerable<T> GetServices<T>(this IServiceProvider provider)
```
-��ȡָ�����͵����з���ʵ����֧��ͬһ�������͵Ķ��ע�ᣩ������˳��Ϊע����������ע������ȷ��أ���
+获取指定类型的所有服务实例(支持同一服务类型的多个注册)。返回顺序为注册的逆序(最后注册的最先返回)。
-**ʾ��**��
+**示例**:
```csharp
-// ע����������
+// 注册多个处理器
ioc.AddSingleton<IMessageHandler, EmailHandler>();
ioc.AddSingleton<IMessageHandler, SmsHandler>();
ioc.AddSingleton<IMessageHandler, PushHandler>();
-// ��ȡ���д�����
+// 获取所有处理器
var handlers = provider.GetServices<IMessageHandler>();
foreach (var handler in handlers)
{
@@ -368,11 +368,11 @@ foreach (var handler in handlers)
}
```
-### ������֧��
+### 作用域支持
-#### IServiceScope �ӿ�
+#### IServiceScope 接口
-��Χ����ӿڣ��÷�Χ���������ڣ�ÿ����������ֻ��һ��ʵ����
+范围服务接口,该范围生命周期内,每个服务类型只有一个实例。
```csharp
public interface IServiceScope : IDisposable
@@ -381,9 +381,9 @@ public interface IServiceScope : IDisposable
}
```
-#### IServiceScopeFactory �ӿ�
+#### IServiceScopeFactory 接口
-��Χ�����ӿڡ�
+范围服务工厂接口。
```csharp
public interface IServiceScopeFactory
@@ -398,15 +398,15 @@ public interface IServiceScopeFactory
IServiceScope? CreateScope(this IServiceProvider provider)
```
-������Χ�������������� Scoped ������ͬһʵ����
+创建范围作用域,该作用域内 Scoped 服务共享同一实例。
-**ʾ��**��
+**示例**:
```csharp
using var scope = provider.CreateScope();
var scopedService = scope.ServiceProvider.GetService<IDbContext>();
-// scopedService �ڴ�����������Ψһ��
+// scopedService 在此作用域内是唯一的
-// ���������ٴλ�ȡ������ͬһʵ��
+// 作用域内再次获取,返回同一实例
var scopedService2 = scope.ServiceProvider.GetService<IDbContext>();
// scopedService == scopedService2
```
@@ -417,55 +417,55 @@ var scopedService2 = scope.ServiceProvider.GetService<IDbContext>();
Object? CreateInstance(this IServiceProvider provider, Type serviceType)
```
-�����������ʹ�÷����ṩ������乹�캯�������������ڴ���δע�����͵�ʵ����
+创建服务对象,使用服务提供者来填充构造函数参数。可用于创建未注册类型的实例。
-**ʾ��**��
+**示例**:
```csharp
-// ����δע�����͵�ʵ�����Զ�ע����ע�������
+// 创建未注册类型的实例,自动注入已注册的依赖
var instance = provider.CreateInstance(typeof(MyController));
```
-## �����������
+## 生命周期详解
-### Singleton��������
+### Singleton(单例)
```csharp
ioc.AddSingleton<IMyService, MyService>();
```
-- **����ʱ��**���״�����ʱ����
-- **ʵ������**������Ӧ�ó���ֻ��һ��ʵ��
-- **�ͷ�ʱ��**��Ӧ�ó������ʱ�ͷ�
-- **���ó���**�����á���־���������״̬��ȫ�ֹ����ķ���
-- **ע������**����������Ӧ�������������
+- **创建时机**:首次请求时创建
+- **实例数量**:整个应用程序只有一个实例
+- **释放时机**:应用程序结束时释放
+- **适用场景**:配置、日志、缓存等无状态或全局共享的服务
+- **注意事项**:单例服务不应依赖作用域服务
-### Transient��˲̬��
+### Transient(瞬态)
```csharp
ioc.AddTransient<IMyService, MyService>();
```
-- **����ʱ��**��ÿ������ʱ����
-- **ʵ������**��ÿ����������ʵ��
-- **�ͷ�ʱ��**��ʹ���꼴�ɱ� GC ����
-- **���ó���**������������״̬�ķ���
-- **ע������**��Ƶ����������Ӱ������
+- **创建时机**:每次请求时创建
+- **实例数量**:每次请求都是新实例
+- **释放时机**:使用完即可被 GC 回收
+- **适用场景**:轻量级、无状态的服务
+- **注意事项**:频繁创建可能影响性能
-### Scoped��������
+### Scoped(作用域)
```csharp
ioc.AddScoped<IMyService, MyService>();
```
-- **����ʱ��**�����������״�����ʱ����
-- **ʵ������**��ÿ��������һ��ʵ��
-- **�ͷ�ʱ��**������������ʱ�ͷ�
-- **���ó���**��Web �������ݿ������ĵ�
-- **ע������**����Ҫͨ�� `CreateScope()` ����������
+- **创建时机**:作用域内首次请求时创建
+- **实例数量**:每个作用域一个实例
+- **释放时机**:作用域销毁时释放
+- **适用场景**:Web 请求、数据库上下文等
+- **注意事项**:需要通过 `CreateScope()` 创建作用域
-## ���캯��ע��
+## 构造函数注入
-ObjectContainer ֧���Զ����캯��ע�룬ѡ��������Ŀ�ƥ�乹�캯����
+ObjectContainer 支持自动构造函数注入,选择参数最多的可匹配构造函数:
```csharp
public interface ILogger { void Log(String message); }
@@ -479,7 +479,7 @@ public class UserRepository : IRepository
{
public ILogger Logger { get; }
- // ���캯��ע��
+ // 构造函数注入
public UserRepository(ILogger logger)
{
Logger = logger;
@@ -491,7 +491,7 @@ public class UserService
public IRepository Repository { get; }
public ILogger Logger { get; }
- // ��������캯��
+ // 多参数构造函数
public UserService(IRepository repository, ILogger logger)
{
Repository = repository;
@@ -499,29 +499,29 @@ public class UserService
}
}
-// ע�����
+// 注册服务
var ioc = ObjectContainer.Current;
ioc.AddSingleton<ILogger, ConsoleLogger>();
ioc.AddSingleton<IRepository, UserRepository>();
ioc.AddSingleton<UserService>();
-// ����ʱ�Զ�ע������
+// 解析时自动注入依赖
var provider = ioc.BuildServiceProvider();
var userService = provider.GetService<UserService>();
-// userService.Logger �� userService.Repository �����Զ�ע��
+// userService.Logger 和 userService.Repository 都已自动注入
```
-### ���캯��ѡ�����
+### 构造函数选择规则
-1. ��ȡ���͵����й���ʵ�����캯��
-2. ������������������
-3. ���γ���ƥ�䣬ѡ���һ�����в������ܽ����Ĺ��캯��
-4. �������Ͳ�����Int32��String��Boolean �ȣ�ʹ��Ĭ��ֵ
-5. ���û�п�ƥ��Ĺ��캯�����׳� `InvalidOperationException`
+1. 获取类型的所有公共实例构造函数
+2. 按参数数量降序排列
+3. 依次尝试匹配,选择第一个所有参数都能解析的构造函数
+4. 基本类型参数(Int32、String、Boolean 等)使用默认值
+5. 如果没有可匹配的构造函数,抛出 `InvalidOperationException`
-### ֧�ֵ�Ĭ�ϲ�������
+### 支持的默认参数类型
-| ���� | Ĭ��ֵ |
+| 类型 | 默认值 |
|------|--------|
| `Boolean` | `false` |
| `Char` | `(Char)0` |
@@ -534,48 +534,48 @@ var userService = provider.GetService<UserService>();
| `DateTime` | `DateTime.MinValue` |
| `String` | `null` |
-## �� ASP.NET Core ����
+## 与 ASP.NET Core 集成
-### ��ʽһ����Ϊ��������
+### 方式一:作为补充容器
```csharp
// Program.cs
var builder = WebApplication.CreateBuilder(args);
-// ʹ�� ASP.NET Core �� DI
+// 使用 ASP.NET Core 的 DI
builder.Services.AddControllers();
builder.Services.AddScoped<IUserService, UserService>();
var app = builder.Build();
-// �����ڲ��ṩ�ߣ�ʵ����ʽ����
+// 设置内部提供者,实现链式查找
ObjectContainer.SetInnerProvider(app.Services);
-// ���� ObjectContainer.Provider ���Խ��� ASP.NET Core ע��ķ���
+// 现在 ObjectContainer.Provider 可以解析 ASP.NET Core 注册的服务
var userService = ObjectContainer.Provider.GetService<IUserService>();
```
-### ��ʽ�����ӳٰ�
+### 方式二:延迟绑定
```csharp
-// �� AddXxx ��ʹ�ù����ӳٰ�
+// 在 AddXxx 阶段使用工厂延迟绑定
ObjectContainer.SetInnerProvider(() => app.Services);
```
-### ��ʽ�������ʹ��
+### 方式三:混合使用
```csharp
-// �� NewLife ������ע��
+// 在 NewLife 容器中注册
ObjectContainer.Current.AddSingleton<ICache, MemoryCache>();
-// �� ASP.NET Core ��Ҳ���Է���
+// 在 ASP.NET Core 中也可以访问
builder.Services.AddSingleton(sp =>
ObjectContainer.Provider.GetService<ICache>()!);
```
-## ʵսʾ��
+## 实战示例
-### 1. ����̨Ӧ��
+### 1. 控制台应用
```csharp
public class Program
@@ -584,12 +584,12 @@ public class Program
{
var ioc = ObjectContainer.Current;
- // ע�����
+ // 注册服务
ioc.AddSingleton<ILogger, ConsoleLogger>();
ioc.AddSingleton<IConfiguration, JsonConfiguration>();
ioc.AddTransient<IUserService, UserService>();
- // ����������
+ // 构建并运行
var provider = ioc.BuildServiceProvider();
var service = provider.GetRequiredService<IUserService>();
service.Process();
@@ -597,27 +597,27 @@ public class Program
}
```
-### 2. Web Ӧ��
+### 2. Web 应用
```csharp
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
- // �� NewLife ������ע��ͬ���� ASP.NET Core
+ // 将 NewLife 容器的注册同步到 ASP.NET Core
var ioc = ObjectContainer.Current;
ioc.AddSingleton<IMyService, MyService>();
- // ���Ƶ� ASP.NET Core ����
+ // 复制到 ASP.NET Core 容器
foreach (var item in ioc.Services)
{
- // ת�������ӵ� services
+ // 转换并添加到 services
}
}
}
```
-### 3. ���ϵͳ
+### 3. 插件系统
```csharp
public class PluginLoader
@@ -654,7 +654,7 @@ public class PluginLoader
}
```
-### 4. ��Ԫ����
+### 4. 单元测试
```csharp
[TestClass]
@@ -667,7 +667,7 @@ public class UserServiceTests
{
var ioc = new ObjectContainer();
- // ע�� Mock ����
+ // 注册 Mock 服务
ioc.AddSingleton<ILogger>(new MockLogger());
ioc.AddSingleton<IRepository>(new MockRepository());
ioc.AddTransient<IUserService, UserService>();
@@ -685,31 +685,31 @@ public class UserServiceTests
}
```
-## ���÷�
+## 高级用法
-### �����滻
+### 服务替换
-ʹ�� `Add` ���������ظ�ע��ͬһ�������ͣ�����ʱ�������ע��ģ�
+使用 `Add` 方法可以重复注册同一服务类型,解析时返回最后注册的:
```csharp
ioc.AddSingleton<ILogger, ConsoleLogger>();
-ioc.AddSingleton<ILogger, FileLogger>(); // �滻
+ioc.AddSingleton<ILogger, FileLogger>(); // 替换
-var logger = provider.GetService<ILogger>(); // ���� FileLogger
+var logger = provider.GetService<ILogger>(); // 返回 FileLogger
```
-### ����ע��
+### 条件注册
-ʹ�� `TryAdd` ʵ������ע�
+使用 `TryAdd` 实现条件注册:
```csharp
-// ����δע��ʱ����Ĭ��ʵ��
+// 仅在未注册时添加默认实现
ioc.TryAddSingleton<ILogger, ConsoleLogger>();
-// �û������ڴ�֮ǰע���Լ���ʵ��
+// 用户可以在此之前注册自己的实现
```
-### ����ģʽ
+### 工厂模式
```csharp
ioc.AddSingleton<IConnectionFactory>(sp =>
@@ -720,13 +720,13 @@ ioc.AddSingleton<IConnectionFactory>(sp =>
});
```
-### װ����ģʽ
+### 装饰器模式
```csharp
-// ע�����ʵ��
+// 注册基础实现
ioc.AddSingleton<ILogger, ConsoleLogger>();
-// ע��װ����
+// 注册装饰器
ioc.AddSingleton<ILogger>(sp =>
{
var services = sp.GetServices<ILogger>().ToList();
@@ -735,92 +735,92 @@ ioc.AddSingleton<ILogger>(sp =>
});
```
-## ���ʵ��
+## 最佳实践
-### �Ƽ�
+### 推荐
-1. **����ʹ�ýӿ�ע��**�����ڲ��Ժ��滻ʵ��
-2. **����ѡ����������**������������״̬����������������״̬����Ҫ�����ķ���
-3. **ʹ�� TryAdd ��ֹ����**���������ʹ�� TryAdd �����û��Զ���ʵ��
-4. **����ע�ᣬ�ӳٽ���**����Ӧ������ʱ�������ע��
+1. **优先使用接口注册**:便于测试和替换实现
+2. **合理选择生命周期**:单例用于无状态服务,作用域用于有状态但需要共享的服务
+3. **使用 TryAdd 防止覆盖**:库代码中使用 TryAdd 允许用户自定义实现
+4. **早期注册,延迟解析**:在应用启动时完成所有注册
-### ����
+### 避免
-1. **�������λ��ģʽ**����Ҫ��ҵ�������ֱ�ӵ��� `ObjectContainer.Provider`
-2. **���ⵥ������������**����������Ӧ�������������
-3. **����ѭ������**��A ���� B��B ���� A �ᵼ�½���ʧ��
-4. **�������ȵ�·��ע��**������ע��Ӧ������ʱ���
+1. **避免服务定位器模式**:不要在业务代码中直接调用 `ObjectContainer.Provider`
+2. **避免单例依赖作用域**:单例服务不应依赖作用域服务
+3. **避免循环依赖**:A 依赖 B,B 依赖 A 会导致解析失败
+4. **避免在热点路径注册**:服务注册应在启动时完成
-### ��������ѡ����
+### 生命周期选择建议
```csharp
-// ���á���־ �� ����
+// 配置、日志 → 单例
ioc.AddSingleton<AppConfig>();
ioc.AddSingleton<ILogger, FileLogger>();
-// ���ݿ������� �� ������Web����˲̬������̨��
+// 数据库上下文 → 作用域(Web)或瞬态(控制台)
ioc.AddScoped<IDbContext, AppDbContext>(); // Web
-ioc.AddTransient<IDbContext, AppDbContext>(); // ����̨
+ioc.AddTransient<IDbContext, AppDbContext>(); // 控制台
-// ҵ�������� �� ˲̬
+// 业务服务对象 → 瞬态
ioc.AddTransient<IValidator, UserValidator>();
```
-## ��������
+## 常见问题
-### Q: ��������ʱ�׳� "No suitable constructor" �쳣
+### Q: 解析服务时抛出 "No suitable constructor" 异常
-**ԭ��**�����캯����ij����������δע�ᡣ
+**原因**:构造函数的某个参数类型未注册。
-**���**��
+**解决**:
```csharp
-// ��鲢ע����������
+// 检查并注册所有依赖
ioc.AddSingleton<IDependency, Dependency>();
```
-### Q: Scoped �����ڵ���������ȷ����
+### Q: Scoped 服务在单例中无法正确工作
-**ԭ��**������������������ڱ�����������й��ڵ�������ʵ����
+**原因**:单例服务的生命周期比作用域长,会持有过期的作用域实例。
-**���**��
+**解决**:
```csharp
-// ���ù���ģʽ
+// 改用工厂模式
ioc.AddSingleton<IServiceFactory>(sp =>
new ServiceFactory(() => sp.CreateScope()));
```
-### Q: ͬһ�ӿ�ע����ʵ�֣�ֻ�ܻ�ȡһ��
+### Q: 同一接口注册多个实现,只能获取一个
-**ԭ��**��`GetService<T>()` ֻ�������ע���ʵ�֡�
+**原因**:`GetService<T>()` 只返回最后注册的实现。
-**���**��
+**解决**:
```csharp
-// ʹ�� GetServices ��ȡ����ʵ��
+// 使用 GetServices 获取所有实现
var services = provider.GetServices<IHandler>();
```
-### Q: ����� ASP.NET Core DI ����
+### Q: 如何与 ASP.NET Core DI 共存
-**���**��ʹ�� `SetInnerProvider` ������ʽ���ң�
+**解决**:使用 `SetInnerProvider` 建立链式查找:
```csharp
ObjectContainer.SetInnerProvider(app.Services);
```
-## �� Microsoft.Extensions.DependencyInjection �Ա�
+## 与 Microsoft.Extensions.DependencyInjection 对比
-| ���� | ObjectContainer | MS DI |
+| 特性 | ObjectContainer | MS DI |
|------|-----------------|-------|
-| ������С | ��С���������� | ��Ҫ����� |
-| �������� | ֧�� | ֧�� |
-| ���캯��ע�� | ֧�� | ֧�� |
-| ����ע�� | ��֧�� | ��֧�� |
-| ����ע�� | ��֧�� | ��֧�� |
-| װ����ģʽ | �ֶ�֧�� | ֧�� |
-| ��֤ | �� | ֧�� |
-| ȫ�ַ��� | ���� | ��Ҫ����ʵ�� |
-
-## �������
-
-- [NewLife.Core ��Ŀ��ҳ](https://github.com/NewLifeX/X)
-- [�����ĵ�](https://newlifex.com/core/object_container)
-- [Ӧ������ IHost](./Ӧ������Host.md)
+| 依赖大小 | 极小(无依赖) | 需要额外包 |
+| 生命周期 | 支持 | 支持 |
+| 构造函数注入 | 支持 | 支持 |
+| 属性注入 | 不支持 | 不支持 |
+| 方法注入 | 不支持 | 不支持 |
+| 装饰器模式 | 手动支持 | 支持 |
+| 验证 | 无 | 支持 |
+| 全局访问 | 内置 | 需要自行实现 |
+
+## 相关链接
+
+- [NewLife.Core 项目主页](https://github.com/NewLifeX/X)
+- [在线文档](https://newlifex.com/core/object_container)
+- [应用主机 IHost](./应用主机Host.md)
diff --git "a/Doc/\345\257\271\350\261\241\346\261\240Pool.md" "b/Doc/\345\257\271\350\261\241\346\261\240Pool.md"
index 70af14d..8a165a3 100644
--- "a/Doc/\345\257\271\350\261\241\346\261\240Pool.md"
+++ "b/Doc/\345\257\271\350\261\241\346\261\240Pool.md"
@@ -1,163 +1,163 @@
-# ����� Pool
+# 对象池 Pool
-## ����
+## 概述
-`Pool<T>` �� NewLife.Core �е������������ʵ�֣���������������ƣ�ͨ�� CAS ����ʵ�ָ����ܵĶ����á�����ؿ�����������Ƶ���������ٶ�������� GC ѹ�����ر��ʺϸ�Ƶ������
+`Pool<T>` 是 NewLife.Core 中的轻量级对象池实现,采用数组无锁设计,通过 CAS 操作实现高性能的对象复用。对象池可以显著减少频繁创建销毁对象带来的 GC 压力,特别适合高频场景。
-**�����ռ�**��`NewLife.Collections`
-**�ĵ���ַ**��https://newlifex.com/core/object_pool
+**命名空间**:`NewLife.Collections`
+**文档地址**:https://newlifex.com/core/object_pool
-## ��������
+## 核心特性
-- **�������**��ʹ�� `Interlocked.CompareExchange` ʵ����������
-- **�ȵ��λ**������ά�����ȶ������������ٶ�
-- **GC �Ѻ�**��֧�ֶ��� GC ʱ�Զ�����
-- **������**��O(N) ɨ�裬�ṹ��������ñ���������
-- **���ó�**���ṩ `StringBuilder`��`MemoryStream` �ȳ��ó�
+- **无锁设计**:使用 `Interlocked.CompareExchange` 实现无锁并发
+- **热点槽位**:单独维护最热对象,提升访问速度
+- **GC 友好**:支持二代 GC 时自动清理
+- **高性能**:O(N) 扫描,结构体持有引用避免额外分配
+- **内置池**:提供 `StringBuilder`、`MemoryStream` 等常用池
-## ���ٿ�ʼ
+## 快速开始
-### ����ʹ��
+### 基本使用
```csharp
using NewLife.Collections;
-// ���������
+// 创建对象池
var pool = new Pool<MyObject>();
-// ��ȡ����
+// 获取对象
var obj = pool.Get();
try
{
- // ʹ�ö���...
+ // 使用对象...
obj.DoSomething();
}
finally
{
- // �黹����
+ // 归还对象
pool.Return(obj);
}
```
-### ʹ������ StringBuilder ��
+### 使用内置 StringBuilder 池
```csharp
using NewLife.Collections;
-// �ӳ��л�ȡ StringBuilder
+// 从池中获取 StringBuilder
var sb = Pool.StringBuilder.Get();
sb.Append("Hello ");
sb.Append("World");
-// �黹����ȡ���
-var result = sb.Return(true); // ���� "Hello World"
+// 归还并获取结果
+var result = sb.Return(true); // 返回 "Hello World"
-// ����Ҫ���ʱ
+// 或不需要结果时
sb.Return(false);
```
-## API �ο�
+## API 参考
-### IPool<T> �ӿ�
+### IPool<T> 接口
```csharp
public interface IPool<T>
{
- /// <summary>����ش�С</summary>
+ /// <summary>对象池大小</summary>
Int32 Max { get; set; }
- /// <summary>��ȡ����</summary>
+ /// <summary>获取对象</summary>
T Get();
- /// <summary>�黹����</summary>
+ /// <summary>归还对象</summary>
Boolean Return(T value);
- /// <summary>��ն����</summary>
+ /// <summary>清空对象池</summary>
Int32 Clear();
}
```
-### Pool<T> ��
+### Pool<T> 类
```csharp
public class Pool<T> : IPool<T> where T : class
{
- /// <summary>����ش�С��Ĭ�� CPU*2����С8</summary>
+ /// <summary>对象池大小。默认 CPU*2,最小8</summary>
public Int32 Max { get; set; }
- /// <summary>��ȡ���ؿ�ʱ������ʵ��</summary>
+ /// <summary>获取对象,池空时创建新实例</summary>
public virtual T Get();
- /// <summary>�黹����</summary>
+ /// <summary>归还对象</summary>
public virtual Boolean Return(T value);
- /// <summary>��ն����</summary>
+ /// <summary>清空对象池</summary>
public virtual Int32 Clear();
- /// <summary>�����������</summary>
+ /// <summary>创建对象(可重写)</summary>
protected virtual T? OnCreate();
}
```
-#### ���캯��
+#### 构造函数
```csharp
-// Ĭ�Ϲ��죬��СΪ CPU*2
+// 默认构造,大小为 CPU*2
var pool = new Pool<MyObject>();
-// ָ����С
+// 指定大小
var pool = new Pool<MyObject>(100);
-// ���� GC ������protected��
+// 启用 GC 清理(protected)
protected Pool(Int32 max, Boolean useGcClear)
```
-## ���ö����
+## 内置对象池
-### StringBuilder ��
+### StringBuilder 池
```csharp
public static class Pool
{
- /// <summary>�ַ�����������</summary>
+ /// <summary>字符串构建器池</summary>
public static IPool<StringBuilder> StringBuilder { get; set; }
}
```
-**ʹ��ʾ��**��
+**使用示例**:
```csharp
var sb = Pool.StringBuilder.Get();
sb.Append("Name: ");
sb.Append(name);
sb.AppendLine();
-// ��ʽ1���黹����ȡ���
+// 方式1:归还并获取结果
var result = sb.Return(true);
-// ��ʽ2�����黹
+// 方式2:仅归还
sb.Return(false);
```
-### StringBuilderPool ��
+### StringBuilderPool 类
```csharp
public class StringBuilderPool : Pool<StringBuilder>
{
- /// <summary>��ʼ������Ĭ��100</summary>
+ /// <summary>初始容量。默认100</summary>
public Int32 InitialCapacity { get; set; }
- /// <summary>�����������������أ�Ĭ��4K</summary>
+ /// <summary>最大容量。超过不入池,默认4K</summary>
public Int32 MaximumCapacity { get; set; }
}
```
-�黹ʱ�Զ�������ݣ�������������IJ�������С�
+归还时自动清空内容,超过最大容量的不放入池中。
-## ʹ�ó���
+## 使用场景
-### 1. ��Ƶ������
+### 1. 高频对象复用
```csharp
public class MessageProcessor
@@ -174,14 +174,14 @@ public class MessageProcessor
}
finally
{
- msg.Reset(); // ����״̬
+ msg.Reset(); // 重置状态
_pool.Return(msg);
}
}
}
```
-### 2. ��������
+### 2. 缓冲区池
```csharp
public class BufferPool : Pool<Byte[]>
@@ -192,23 +192,23 @@ public class BufferPool : Pool<Byte[]>
public override Boolean Return(Byte[] value)
{
- // ��С��ƥ�䲻���
+ // 大小不匹配不入池
if (value.Length != BufferSize) return false;
- // �������
+ // 清空数据
Array.Clear(value, 0, value.Length);
return base.Return(value);
}
}
-// ʹ��
+// 使用
var bufferPool = new BufferPool { BufferSize = 8192 };
var buffer = bufferPool.Get();
try
{
var read = stream.Read(buffer, 0, buffer.Length);
- // ��������...
+ // 处理数据...
}
finally
{
@@ -216,7 +216,7 @@ finally
}
```
-### 3. ���ݿ����ӳ�
+### 3. 数据库连接池
```csharp
public class ConnectionPool : Pool<DbConnection>
@@ -232,7 +232,7 @@ public class ConnectionPool : Pool<DbConnection>
public override Boolean Return(DbConnection value)
{
- // �����ѶϿ������
+ // 连接已断开则不入池
if (value.State != ConnectionState.Open) return false;
return base.Return(value);
@@ -240,7 +240,7 @@ public class ConnectionPool : Pool<DbConnection>
}
```
-### 4. ��ʱ����
+### 4. 临时集合
```csharp
public class ListPool<T> : Pool<List<T>>
@@ -258,14 +258,14 @@ public class ListPool<T> : Pool<List<T>>
}
}
-// ʹ��
+// 使用
var listPool = new ListPool<Int32>();
var list = listPool.Get();
try
{
list.Add(1);
list.Add(2);
- // ����...
+ // 处理...
}
finally
{
@@ -273,7 +273,7 @@ finally
}
```
-### 5. ��� using ģʽ
+### 5. 结合 using 模式
```csharp
public class PooledObject<T> : IDisposable where T : class
@@ -293,7 +293,7 @@ public class PooledObject<T> : IDisposable where T : class
}
}
-// ʹ��
+// 使用
using (var pooled = new PooledObject<StringBuilder>(Pool.StringBuilder))
{
pooled.Value.Append("Hello");
@@ -301,16 +301,16 @@ using (var pooled = new PooledObject<StringBuilder>(Pool.StringBuilder))
}
```
-## �Զ�������
+## 自定义对象池
```csharp
public class MyObjectPool : Pool<MyObject>
{
- public MyObjectPool() : base(100) { } // �ش�С100
+ public MyObjectPool() : base(100) { } // 池大小100
protected override MyObject OnCreate()
{
- // �Զ��崴����
+ // 自定义创建逻辑
return new MyObject
{
Id = Guid.NewGuid(),
@@ -320,10 +320,10 @@ public class MyObjectPool : Pool<MyObject>
public override Boolean Return(MyObject value)
{
- // �黹ǰ���ö���
+ // 归还前重置对象
value.Reset();
- // ��֤����״̬
+ // 验证对象状态
if (!value.IsValid) return false;
return base.Return(value);
@@ -331,14 +331,14 @@ public class MyObjectPool : Pool<MyObject>
}
```
-## ������
+## 性能优化
-### 1. Ԥ�ȶ����
+### 1. 预热对象池
```csharp
var pool = new Pool<MyObject>(50);
-// Ԥ�ȣ�����һ������������
+// 预热:创建一批对象放入池中
for (var i = 0; i < 50; i++)
{
var obj = new MyObject();
@@ -346,21 +346,21 @@ for (var i = 0; i < 50; i++)
}
```
-### 2. �������ô�С
+### 2. 合理设置大小
```csharp
-// ���ݲ���������
+// 根据并发量设置
var pool = new Pool<MyObject>(Environment.ProcessorCount * 4);
```
-### 3. ��������
+### 3. 避免大对象
```csharp
-// ��������Ӱ�� GC������ʹ�� ArrayPool
+// 大对象可能影响 GC,考虑使用 ArrayPool
var buffer = ArrayPool<Byte>.Shared.Rent(1024 * 1024);
try
{
- // ʹ�û�����
+ // 使用缓冲区
}
finally
{
@@ -368,26 +368,26 @@ finally
}
```
-## �� ArrayPool �Ա�
+## 与 ArrayPool 对比
-| ���� | Pool<T> | ArrayPool<T> |
+| 特性 | Pool<T> | ArrayPool<T> |
|------|--------------|-------------------|
-| Ŀ������ | �������� | ���� |
-| �̰߳�ȫ | �ǣ�CAS�� | �� |
-| GC ���� | ��ѡ | �Զ� |
-| ��С���� | �̶� | ��̬ |
-| ���� | ������ | ������ |
+| 目标类型 | 引用类型 | 数组 |
+| 线程安全 | 是(CAS) | 是 |
+| GC 清理 | 可选 | 自动 |
+| 大小调整 | 固定 | 动态 |
+| 适用场景 | 对象复用 | 缓冲区 |
-## ���ʵ��
+## 最佳实践
-1. **��ʱ�黹**��ʹ�� try-finally ȷ������黹
-2. **����״̬**���黹ǰ���������ڲ�״̬
-3. **��֤����**���黹ʱ��������Ч��
-4. **������С**�����ݲ��������óش�С
-5. **����й©**��ȷ���쳣·��Ҳ�ܹ黹����
+1. **及时归还**:使用 try-finally 确保对象归还
+2. **重置状态**:归还前清理对象内部状态
+3. **验证对象**:归还时检查对象有效性
+4. **合理大小**:根据并发量设置池大小
+5. **避免泄漏**:确保异常路径也能归还对象
-## �������
+## 相关链接
-- [����ϵͳ ICache](cache-����ϵͳICache.md)
-- [�ַ�����չ StringHelper](string_helper-�ַ�����չStringHelper.md)
-- [������չ IOHelper](io_helper-������չIOHelper.md)
+- [缓存系统 ICache](cache-缓存系统ICache.md)
+- [字符串扩展 StringHelper](string_helper-字符串扩展StringHelper.md)
+- [数据扩展 IOHelper](io_helper-数据扩展IOHelper.md)
diff --git "a/Doc/\345\271\266\350\241\214\346\250\241\345\236\213Actor.md" "b/Doc/\345\271\266\350\241\214\346\250\241\345\236\213Actor.md"
index 4705529..6b076e8 100644
--- "a/Doc/\345\271\266\350\241\214\346\250\241\345\236\213Actor.md"
+++ "b/Doc/\345\271\266\350\241\214\346\250\241\345\236\213Actor.md"
@@ -1,194 +1,194 @@
-# ����� Actor
+# 并行模型 Actor
-## ����
+## 概述
-`Actor` �� NewLife.Core �е��������б��ģ�ͣ�������Ϣ����ʵ���̰߳�ȫ���첽������ÿ�� Actor ӵ�ж�������Ϣ����ʹ����̣߳�ͨ����Ϣ���ݽ���ͨ�ţ������˴�ͳ�����ƴ����ĸ����Ժ��������⡣
+`Actor` 是 NewLife.Core 中的无锁并行编程模型,基于消息队列实现线程安全的异步处理。每个 Actor 拥有独立的消息邮箱和处理线程,通过消息传递进行通信,避免了传统锁机制带来的复杂性和性能问题。
-**�����ռ�**��`NewLife.Model`
-**�ĵ���ַ**��https://newlifex.com/core/actor
+**命名空间**:`NewLife.Model`
+**文档地址**:https://newlifex.com/core/actor
-## ��������
+## 核心特性
-- **�������**��ͨ����Ϣ���и���״̬��������ʽ����
-- **�����߳�**��ÿ�� Actor ʹ�ö����̴߳�����Ϣ����Ӱ���̳߳�
-- **��������**��֧������������Ϣ�����������
-- **��������**��֧��������Ϣ���������������ֹ�ڴ����
-- **�Զ�����**��������Ϣʱ�Զ����� Actor
-- **������**������ `ITracer` ֧����·��
+- **无锁设计**:通过消息队列隔离状态,无需显式加锁
+- **独立线程**:每个 Actor 使用独立线程处理消息,不影响线程池
+- **批量处理**:支持批量消费消息,提高吞吐量
+- **容量限制**:支持设置消息队列最大容量,防止内存溢出
+- **自动启动**:发送消息时自动启动 Actor
+- **性能追踪**:集成 `ITracer` 支持链路追踪
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife.Model;
-// ���� Actor
+// 定义 Actor
public class MyActor : Actor
{
protected override Task ReceiveAsync(ActorContext context, CancellationToken cancellationToken)
{
var message = context.Message;
- Console.WriteLine($"�յ���Ϣ: {message}");
+ Console.WriteLine($"收到消息: {message}");
return Task.CompletedTask;
}
}
-// ʹ�� Actor
+// 使用 Actor
var actor = new MyActor();
-// ������Ϣ
+// 发送消息
actor.Tell("Hello");
actor.Tell("World");
-// �ȴ�������ɺ�ֹͣ
+// 等待处理完成后停止
actor.Stop(5000);
```
-## API �ο�
+## API 参考
-### IActor �ӿ�
+### IActor 接口
```csharp
public interface IActor
{
- /// <summary>������Ϣ�������ڲ�����</summary>
- /// <param name="message">��Ϣ����</param>
- /// <param name="sender">������Actor</param>
- /// <returns>���ش�������Ϣ��</returns>
+ /// <summary>添加消息,驱动内部处理</summary>
+ /// <param name="message">消息对象</param>
+ /// <param name="sender">发送者Actor</param>
+ /// <returns>返回待处理消息数</returns>
Int32 Tell(Object message, IActor? sender = null);
}
```
-### ActorContext ��
+### ActorContext 类
```csharp
public class ActorContext
{
- /// <summary>������</summary>
+ /// <summary>发送者</summary>
public IActor? Sender { get; set; }
- /// <summary>��Ϣ</summary>
+ /// <summary>消息</summary>
public Object? Message { get; set; }
}
```
-### Actor ����
+### Actor 基类
-#### ����
+#### 属性
```csharp
-/// <summary>����</summary>
+/// <summary>名称</summary>
public String Name { get; set; }
-/// <summary>�Ƿ�����</summary>
+/// <summary>是否启用</summary>
public Boolean Active { get; }
-/// <summary>�������������ɶѻ�����Ϣ����Ĭ��Int32.MaxValue</summary>
+/// <summary>受限容量。最大可堆积的消息数,默认Int32.MaxValue</summary>
public Int32 BoundedCapacity { get; set; }
-/// <summary>����С��ÿ�δ�����Ϣ����Ĭ��1</summary>
+/// <summary>批大小。每次处理消息数,默认1</summary>
public Int32 BatchSize { get; set; }
-/// <summary>�Ƿ�ʱ�����С�Ĭ��true��ʹ�ö����߳�</summary>
+/// <summary>是否长时间运行。默认true,使用独立线程</summary>
public Boolean LongRunning { get; set; }
-/// <summary>��ǰ���г���</summary>
+/// <summary>当前队列长度</summary>
public Int32 QueueLength { get; }
-/// <summary>��������</summary>
+/// <summary>性能追踪器</summary>
public ITracer? Tracer { get; set; }
```
-#### Tell - ������Ϣ
+#### Tell - 发送消息
```csharp
public virtual Int32 Tell(Object message, IActor? sender = null)
```
-�� Actor ������Ϣ����� Actor δ���������Զ�������
+向 Actor 发送消息。如果 Actor 未启动,会自动启动。
-**����**��
-- `message`����Ϣ����������������
-- `sender`�������� Actor�����ڻظ���Ϣ
+**参数**:
+- `message`:消息对象,可以是任意类型
+- `sender`:发送者 Actor,用于回复消息
-**����ֵ**����ǰ����������Ϣ��
+**返回值**:当前待处理的消息数
-**ʾ��**��
+**示例**:
```csharp
var actor = new MyActor();
-// ���ͼ���Ϣ
+// 发送简单消息
actor.Tell("Hello");
-// �����Ӷ���
+// 发送复杂对象
actor.Tell(new { Id = 1, Name = "Test" });
-// ��������
+// 带发送者
actor.Tell("Ping", senderActor);
```
-#### Start - ���� Actor
+#### Start - 启动 Actor
```csharp
public virtual Task? Start()
public virtual Task? Start(CancellationToken cancellationToken)
```
-�ֶ����� Actor��ͨ������Ҫ�ֶ����ã�`Tell` ���Զ�������
+手动启动 Actor。通常不需要手动调用,`Tell` 会自动启动。
-**ʾ��**��
+**示例**:
```csharp
var actor = new MyActor();
-// �ֶ�����
+// 手动启动
actor.Start();
-// ��ȡ����������
+// 带取消令牌启动
using var cts = new CancellationTokenSource();
actor.Start(cts.Token);
```
-#### Stop - ֹͣ Actor
+#### Stop - 停止 Actor
```csharp
public virtual Boolean Stop(Int32 msTimeout = 0)
```
-ֹͣ Actor�����ٽ�������Ϣ��
+停止 Actor,不再接受新消息。
-**����**��
-- `msTimeout`���ȴ���������0=���ȴ���-1=���ȴ�
+**参数**:
+- `msTimeout`:等待毫秒数。0=不等待,-1=无限等待
-**����ֵ**���Ƿ��ڳ�ʱǰ���������Ϣ����
+**返回值**:是否在超时前完成所有消息处理
-**ʾ��**��
+**示例**:
```csharp
-// ����ֹͣ�����ȴ�
+// 立即停止,不等待
actor.Stop(0);
-// �ȴ����5��
+// 等待最多5秒
var completed = actor.Stop(5000);
if (!completed)
- Console.WriteLine("����Ϣδ�������");
+ Console.WriteLine("有消息未处理完成");
-// ���ȴ�
+// 无限等待
actor.Stop(-1);
```
-#### ReceiveAsync - ������Ϣ
+#### ReceiveAsync - 处理消息
```csharp
-// ����������BatchSize=1��
+// 单条处理(BatchSize=1)
protected virtual Task ReceiveAsync(ActorContext context, CancellationToken cancellationToken)
-// ����������BatchSize>1��
+// 批量处理(BatchSize>1)
protected virtual Task ReceiveAsync(ActorContext[] contexts, CancellationToken cancellationToken)
```
-������д�˷���ʵ����Ϣ��������
+子类重写此方法实现消息处理逻辑。
-## ʹ�ó���
+## 使用场景
-### 1. ��־�ռ���
+### 1. 日志收集器
```csharp
public class LogActor : Actor
@@ -198,8 +198,8 @@ public class LogActor : Actor
public LogActor(String filePath)
{
Name = "LogActor";
- BatchSize = 100; // �����
- BoundedCapacity = 10000; // ���ƶ���
+ BatchSize = 100; // 批量写入
+ BoundedCapacity = 10000; // 限制队列
_writer = new StreamWriter(filePath, true) { AutoFlush = false };
}
@@ -223,13 +223,13 @@ public class LogActor : Actor
}
}
-// ʹ��
+// 使用
var logger = new LogActor("app.log");
-logger.Tell($"[{DateTime.Now:HH:mm:ss}] Ӧ������");
-logger.Tell($"[{DateTime.Now:HH:mm:ss}] ��������");
+logger.Tell($"[{DateTime.Now:HH:mm:ss}] 应用启动");
+logger.Tell($"[{DateTime.Now:HH:mm:ss}] 处理请求");
```
-### 2. ��Ϣ������
+### 2. 消息处理器
```csharp
public class MessageProcessor : Actor
@@ -250,7 +250,7 @@ public class MessageProcessor : Actor
{
await _handler.HandleAsync(msg, cancellationToken);
- // �ظ�������
+ // 回复发送者
context.Sender?.Tell(new Ack { MessageId = msg.Id });
}
catch (Exception ex)
@@ -262,7 +262,7 @@ public class MessageProcessor : Actor
}
```
-### 3. ���ݾۺ���
+### 3. 数据聚合器
```csharp
public class DataAggregator : Actor
@@ -287,7 +287,7 @@ public class DataAggregator : Actor
}
}
- // ÿ�������һ��ͳ��
+ // 每分钟输出一次统计
if ((DateTime.Now - _lastFlush).TotalMinutes >= 1)
{
foreach (var kv in _counts)
@@ -303,7 +303,7 @@ public class DataAggregator : Actor
}
```
-### 4. Actor ֮��ͨ��
+### 4. Actor 之间通信
```csharp
public class PingActor : Actor
@@ -312,7 +312,7 @@ public class PingActor : Actor
{
if (context.Message is String msg && msg == "Ping")
{
- Console.WriteLine("PingActor �յ� Ping������ Pong");
+ Console.WriteLine("PingActor 收到 Ping,发送 Pong");
context.Sender?.Tell("Pong", this);
}
return Task.CompletedTask;
@@ -325,21 +325,21 @@ public class PongActor : Actor
{
if (context.Message is String msg && msg == "Pong")
{
- Console.WriteLine("PongActor �յ� Pong");
+ Console.WriteLine("PongActor 收到 Pong");
}
return Task.CompletedTask;
}
}
-// ʹ��
+// 使用
var ping = new PingActor();
var pong = new PongActor();
-// pong ���� Ping �� ping��ping ��ظ� Pong
+// pong 发送 Ping 给 ping,ping 会回复 Pong
ping.Tell("Ping", pong);
```
-### 5. ����������
+### 5. 限流处理器
```csharp
public class RateLimitedActor : Actor
@@ -380,56 +380,56 @@ public class RateLimitedActor : Actor
private async Task ProcessAsync(Object? message, CancellationToken cancellationToken)
{
- // ������
+ // 处理逻辑
await Task.Delay(100, cancellationToken);
}
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ������������С
+### 1. 合理设置批大小
```csharp
-// IO�ܼ��ͣ��ϴ�����
+// IO密集型:较大批次
var ioActor = new IoActor { BatchSize = 100 };
-// CPU�ܼ��ͣ���С����
+// CPU密集型:较小批次
var cpuActor = new CpuActor { BatchSize = 10 };
-// ʵʱ��Ҫ��ߣ���������
+// 实时性要求高:单条处理
var realtimeActor = new RealtimeActor { BatchSize = 1 };
```
-### 2. ���ö�������
+### 2. 设置队列容量
```csharp
-// ��ֹ�ڴ����
+// 防止内存溢出
var actor = new MyActor
{
- BoundedCapacity = 10000 // ���ѻ�1������Ϣ
+ BoundedCapacity = 10000 // 最多堆积1万条消息
};
-// �������
+// 检查队列长度
if (actor.QueueLength > 5000)
{
- Console.WriteLine("���棺��Ϣ��ѹ");
+ Console.WriteLine("警告:消息积压");
}
```
-### 3. ����ֹͣ
+### 3. 优雅停止
```csharp
-// ֹͣ��������Ϣ���ȴ�������Ϣ�������
-var completed = actor.Stop(30_000); // ����30��
+// 停止接收新消息,等待现有消息处理完成
+var completed = actor.Stop(30_000); // 最多等30秒
if (!completed)
{
- Console.WriteLine($"�� {actor.QueueLength} ����Ϣδ����");
+ Console.WriteLine($"有 {actor.QueueLength} 条消息未处理");
}
```
-### 4. �쳣����
+### 4. 异常处理
```csharp
public class SafeActor : Actor
@@ -442,10 +442,10 @@ public class SafeActor : Actor
}
catch (Exception ex)
{
- // ��¼��־�����׳��쳣
+ // 记录日志,不抛出异常
XTrace.WriteException(ex);
- // ��ѡ�����͵����Ŷ���
+ // 可选:发送到死信队列
DeadLetterActor?.Tell(new DeadLetter
{
Message = context.Message,
@@ -456,32 +456,32 @@ public class SafeActor : Actor
}
```
-### 5. ������
+### 5. 性能追踪
```csharp
var actor = new MyActor
{
- Tracer = new DefaultTracer() // ��ʹ���dz���
+ Tracer = new DefaultTracer() // 或使用星尘追踪
};
-// ����Ϣ���Զ���¼��
+// 追踪信息会自动记录:
// - actor:Start
// - actor:Loop
// - actor:Stop
```
-## ����������ģ�ͶԱ�
+## 与其他并发模型对比
-| ���� | Actor | Task/async | �� |
+| 特性 | Actor | Task/async | 锁 |
|------|-------|------------|-----|
-| �̰߳�ȫ | ��Ȼ��ȫ | ��Ҫע�� | ��Ҫ��ʽ���� |
-| ��̸��Ӷ� | �е� | �� | �� |
-| ���ó��� | IO�ܼ� | ͨ�� | ����״̬ |
-| ��ѹ���� | ֧�� | ��֧�� | ��֧�� |
-| ��Ϣ˳�� | ��֤ | ����֤ | ������ |
+| 线程安全 | 天然安全 | 需要注意 | 需要显式加锁 |
+| 编程复杂度 | 中等 | 低 | 高 |
+| 适用场景 | IO密集 | 通用 | 共享状态 |
+| 背压处理 | 支持 | 不支持 | 不支持 |
+| 消息顺序 | 保证 | 不保证 | 不适用 |
-## �������
+## 相关链接
-- [����ʱ�� TimerX](timerx-����ʱ��TimerX.md)
-- [������Ӧ������ Host](host-������Ӧ������Host.md)
-- [��·�� ITracer](tracer-��·��ITracer.md)
+- [高级定时器 TimerX](timerx-高级定时器TimerX.md)
+- [轻量级应用主机 Host](host-轻量级应用主机Host.md)
+- [链路追踪 ITracer](tracer-链路追踪ITracer.md)
diff --git "a/Doc/\346\213\274\351\237\263\345\272\223PinYin.md" "b/Doc/\346\213\274\351\237\263\345\272\223PinYin.md"
index 1df4fb2..863e18e 100644
--- "a/Doc/\346\213\274\351\237\263\345\272\223PinYin.md"
+++ "b/Doc/\346\213\274\351\237\263\345\272\223PinYin.md"
@@ -1,78 +1,78 @@
-# ƴ���� PinYin
+# 拼音库 PinYin
-## ����
+## 概述
-`PinYin` �� NewLife.Core �еĺ���ƴ��ת�������࣬�ṩ��Ч�ĺ���תƴ�����ܡ�֧�� GB2312 һ���Ͷ������֣��ܹ���ȡ���ֵ�ȫƴ��ƴ������ĸ���������������������뷨�ȳ�����
+`PinYin` 是 NewLife.Core 中的汉字拼音转换工具类,提供高效的汉字转拼音功能。支持 GB2312 一级和二级汉字,能够获取汉字的全拼或拼音首字母,适用于搜索、排序、输入法等场景。
-**�����ռ�**��`NewLife.Common`
-**�ĵ���ַ**��https://newlifex.com/core/pinyin
+**命名空间**:`NewLife.Common`
+**文档地址**:https://newlifex.com/core/pinyin
-## ��������
+## 核心特性
-- **������**������ GB2312 �������λ���㷨��������ش����ֵ��ļ�
-- **ȫ����֧��**������ GB2312 һ�����֣�3755�����Ͷ������֣�3008����
-- **�������**��֧��ȫƴ������ĸ������ƴ���ȶ�����ʽ
-- **������**�����ⲿ���������㷨ʵ��
-- **�����**��֧��"����"�ȶ����ֵij�������
+- **高性能**:基于 GB2312 编码和区位码算法,无需加载大型字典文件
+- **全汉字支持**:覆盖 GB2312 一级汉字(3755个)和二级汉字(3008个)
+- **多种输出**:支持全拼、首字母、单字拼音等多种形式
+- **轻量级**:无外部依赖,纯算法实现
+- **特殊处理**:支持"重庆"等多音字的常见读音
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife.Common;
-// ��ȡ����ƴ��
-var py = PinYin.Get('��'); // "Zhong"
+// 获取单字拼音
+var py = PinYin.Get('中'); // "Zhong"
-// ��ȡ�ַ���ȫƴ
-var fullPy = PinYin.Get("������"); // "XinShengMing"
+// 获取字符串全拼
+var fullPy = PinYin.Get("新生命"); // "XinShengMing"
-// ��ȡƴ������ĸ
-var first = PinYin.GetFirst("������"); // "XSM"
+// 获取拼音首字母
+var first = PinYin.GetFirst("新生命"); // "XSM"
-// ��ȡƴ������
-var arr = PinYin.GetAll("���"); // ["Ni", "Hao"]
+// 获取拼音数组
+var arr = PinYin.GetAll("你好"); // ["Ni", "Hao"]
```
-## API �ο�
+## API 参考
-### Get������ƴ����
+### Get(单字拼音)
```csharp
public static String Get(Char ch)
```
-��ȡ�������ֵ�ƴ����
+获取单个汉字的拼音。
-**����˵��**��
-- `ch`��Ҫת�����ַ�
+**参数说明**:
+- `ch`:要转换的字符
-**����ֵ**��
-- ���ַ�������ĸ��д��ƴ������ "Zhong"��
-- �����ַ�����㡢�������ַ�ԭ������
-- ��ʶ��ĺ��ַ��ؿ��ַ���
+**返回值**:
+- 汉字返回首字母大写的拼音(如 "Zhong")
+- 拉丁字符、标点、非中文字符原样返回
+- 无法识别的汉字返回空字符串
-**ʾ��**��
+**示例**:
```csharp
-PinYin.Get('��') // "Zhong"
-PinYin.Get('��') // "Guo"
+PinYin.Get('中') // "Zhong"
+PinYin.Get('国') // "Guo"
PinYin.Get('A') // "A"
-PinYin.Get('��') // "��"
-PinYin.Get('��') // "��"
+PinYin.Get(',') // ","
+PinYin.Get('①') // "①"
```
-### Get���ַ���ȫƴ��
+### Get(字符串全拼)
```csharp
public static String Get(String str)
```
-��ȡ�ַ���������ƴ��������ƴ��ֱ�����ӡ�
+获取字符串的完整拼音,各字拼音直接连接。
-**ʾ��**��
+**示例**:
```csharp
-PinYin.Get("�й�") // "ZhongGuo"
-PinYin.Get("�������Ŷ�") // "XinShengMingTuanDui"
-PinYin.Get("Hello����") // "HelloShiJie"
+PinYin.Get("中国") // "ZhongGuo"
+PinYin.Get("新生命团队") // "XinShengMingTuanDui"
+PinYin.Get("Hello世界") // "HelloShiJie"
```
### GetAll
@@ -81,60 +81,60 @@ PinYin.Get("Hello
public static String[] GetAll(String str)
```
-��ȡ�ַ�����ÿ���ַ���ƴ���������ַ������顣
+获取字符串中每个字符的拼音,返回字符串数组。
-**�����**��
-- "����" �����Ϊ ["Chong", "Qing"]
+**特殊处理**:
+- "重庆" 特殊处理为 ["Chong", "Qing"]
-**ʾ��**��
+**示例**:
```csharp
-PinYin.GetAll("���") // ["Ni", "Hao"]
-PinYin.GetAll("����") // ["Chong", "Qing"]
+PinYin.GetAll("你好") // ["Ni", "Hao"]
+PinYin.GetAll("重庆") // ["Chong", "Qing"]
PinYin.GetAll("ABC") // ["A", "B", "C"]
PinYin.GetAll("Hello") // ["H", "e", "l", "l", "o"]
```
-### GetFirst��ƴ������ĸ��
+### GetFirst(拼音首字母)
```csharp
public static Char GetFirst(Char ch)
public static String GetFirst(String str)
```
-��ȡ���ֻ��ַ�����ƴ������ĸ��
+获取汉字或字符串的拼音首字母。
-**ʾ��**��
+**示例**:
```csharp
-// ��������ĸ
-PinYin.GetFirst('��') // 'Z'
-PinYin.GetFirst('��') // 'G'
+// 单字首字母
+PinYin.GetFirst('中') // 'Z'
+PinYin.GetFirst('国') // 'G'
PinYin.GetFirst('A') // 'A'
-// �ַ�������ĸ
-PinYin.GetFirst("������") // "XSM"
-PinYin.GetFirst("�й�") // "ZG"
+// 字符串首字母
+PinYin.GetFirst("新生命") // "XSM"
+PinYin.GetFirst("中国") // "ZG"
PinYin.GetFirst("Hello") // "Hello"
```
-## ʹ�ó���
+## 使用场景
-### 1. ����ƥ��
+### 1. 搜索匹配
```csharp
public class UserService
{
- /// <summary>����ƴ������ĸ�����û�</summary>
+ /// <summary>根据拼音首字母搜索用户</summary>
public List<User> SearchByPinyin(List<User> users, String keyword)
{
var upperKeyword = keyword.ToUpper();
return users.Where(u =>
{
- // ȫ��ƥ��
+ // 全名匹配
if (u.Name.Contains(keyword, StringComparison.OrdinalIgnoreCase))
return true;
- // ƴ������ĸƥ��
+ // 拼音首字母匹配
var firstLetters = PinYin.GetFirst(u.Name);
return firstLetters.Contains(upperKeyword, StringComparison.OrdinalIgnoreCase);
@@ -142,24 +142,24 @@ public class UserService
}
}
-// ʹ��ʾ��
+// 使用示例
var users = new List<User>
{
- new User { Name = "����" },
- new User { Name = "����" },
- new User { Name = "����" }
+ new User { Name = "张三" },
+ new User { Name = "李四" },
+ new User { Name = "王五" }
};
-var result = service.SearchByPinyin(users, "ZS"); // �ҵ� "����"
-var result2 = service.SearchByPinyin(users, "LS"); // �ҵ� "����"
+var result = service.SearchByPinyin(users, "ZS"); // 找到 "张三"
+var result2 = service.SearchByPinyin(users, "LS"); // 找到 "李四"
```
-### 2. ��ƴ������
+### 2. 按拼音排序
```csharp
public class ProductSorter
{
- /// <summary>��ƴ��������Ʒ����</summary>
+ /// <summary>按拼音排序商品名称</summary>
public List<Product> SortByPinyin(List<Product> products)
{
return products
@@ -168,24 +168,24 @@ public class ProductSorter
}
}
-// ʹ��ʾ��
+// 使用示例
var products = new List<Product>
{
- new Product { Name = "ƻ��" },
- new Product { Name = "�㽶" },
- new Product { Name = "����" }
+ new Product { Name = "苹果" },
+ new Product { Name = "香蕉" },
+ new Product { Name = "橙子" }
};
var sorted = sorter.SortByPinyin(products);
-// ������������(ChengZi) -> ƻ��(PingGuo) -> �㽶(XiangJiao)
+// 排序结果:橙子(ChengZi) -> 苹果(PingGuo) -> 香蕉(XiangJiao)
```
-### 3. ����ƴ������
+### 3. 生成拼音索引
```csharp
public class ContactIndexer
{
- /// <summary>������ϵ��ƴ������</summary>
+ /// <summary>生成联系人拼音索引</summary>
public Dictionary<Char, List<Contact>> BuildIndex(List<Contact> contacts)
{
var index = new Dictionary<Char, List<Contact>>();
@@ -204,20 +204,20 @@ public class ContactIndexer
}
}
-// ʹ��ʾ��
+// 使用示例
var contacts = new List<Contact>
{
- new Contact { Name = "����" },
- new Contact { Name = "����" },
- new Contact { Name = "����" }
+ new Contact { Name = "张三" },
+ new Contact { Name = "赵四" },
+ new Contact { Name = "李五" }
};
var index = indexer.BuildIndex(contacts);
-// index['Z'] = [����, ����]
-// index['L'] = [����]
+// index['Z'] = [张三, 赵四]
+// index['L'] = [李五]
```
-### 4. ���뷨��ʾ
+### 4. 输入法提示
```csharp
public class InputSuggestion
@@ -229,7 +229,7 @@ public class InputSuggestion
_words = words;
}
- /// <summary>���������ȡ�����</summary>
+ /// <summary>根据输入获取建议词</summary>
public List<String> GetSuggestions(String input)
{
if (input.IsNullOrEmpty()) return new List<String>();
@@ -239,12 +239,12 @@ public class InputSuggestion
return _words
.Where(w =>
{
- // ֧������ĸƥ��
+ // 支持首字母匹配
var first = PinYin.GetFirst(w);
if (first.StartsWith(upperInput, StringComparison.OrdinalIgnoreCase))
return true;
- // ֧��ȫƴƥ��
+ // 支持全拼匹配
var full = PinYin.Get(w);
return full.StartsWith(upperInput, StringComparison.OrdinalIgnoreCase);
})
@@ -253,15 +253,15 @@ public class InputSuggestion
}
}
-// ʹ��ʾ��
-var words = new List<String> { "������", "�����", "��������", "���տ���" };
+// 使用示例
+var words = new List<String> { "新生命", "新年好", "新手入门", "生日快乐" };
var suggester = new InputSuggestion(words);
-suggester.GetSuggestions("XS"); // ["������", "��������"]
-suggester.GetSuggestions("Xin"); // ["������", "�����", "��������"]
+suggester.GetSuggestions("XS"); // ["新生命", "新手入门"]
+suggester.GetSuggestions("Xin"); // ["新生命", "新年好", "新手入门"]
```
-### 5. ���ݿ�洢�Ż�
+### 5. 数据库存储优化
```csharp
public class User
@@ -269,13 +269,13 @@ public class User
public Int32 Id { get; set; }
public String Name { get; set; }
- /// <summary>����ƴ��������������</summary>
+ /// <summary>姓名拼音(用于搜索)</summary>
public String NamePinyin { get; set; }
- /// <summary>��������ĸ������������</summary>
+ /// <summary>姓名首字母(用于索引)</summary>
public String NameFirst { get; set; }
- /// <summary>����ǰ�Զ�����ƴ���ֶ�</summary>
+ /// <summary>保存前自动生成拼音字段</summary>
public void BeforeSave()
{
NamePinyin = PinYin.Get(Name);
@@ -283,85 +283,85 @@ public class User
}
}
-// ���ݿ��ѯʱ������ƴ���ֶμ�������
+// 数据库查询时可利用拼音字段加速搜索
// SELECT * FROM Users WHERE NameFirst LIKE 'ZS%'
// SELECT * FROM Users WHERE NamePinyin LIKE 'Zhang%'
```
-## ����ϸ��
+## 技术细节
-### �������
+### 编码基础
-PinYin ����� GB2312 ����ʵ�֣�
+PinYin 类基于 GB2312 编码实现:
-1. **һ������**���� 3755 ������ƴ��˳������
-2. **��������**���� 3008 ���������ױʻ�˳������
-3. **���⺺��**������ GB2312 ��Χ�ij��ú��ֵ�������
+1. **一级汉字**:共 3755 个,按拼音顺序排列
+2. **二级汉字**:共 3008 个,按部首笔画顺序排列
+3. **特殊汉字**:超出 GB2312 范围的常用汉字单独处理
-### �㷨ԭ��
+### 算法原理
```
-�ַ� �� GB2312���� �� ��λ�� �� ƴ��ӳ��
+字符 → GB2312编码 → 区位码 → 拼音映射
```
-1. ������ת��Ϊ GB2312 �ֽ�
-2. ������λ�루���ֽ�����ټ�ƫ�ƣ�
-3. һ������ͨ������ӳ����ٶ�λƴ��
-4. ��������ͨ��������һ�ȡƴ��
+1. 将汉字转换为 GB2312 字节
+2. 计算区位码(两字节相乘再减偏移)
+3. 一级汉字通过区间映射快速定位拼音
+4. 二级汉字通过数组查找获取拼音
-### �����ص�
+### 性能特点
-- **���ֵ����**���㷨ֱ�Ӽ��㣬����������
-- **O(1) ���Ӷ�**��һ������ͨ���ֿ��㷨���ٶ�λ
-- **�ڴ�ռ��С**�����洢ƴ����������
+- **无字典加载**:算法直接计算,启动即可用
+- **O(1) 复杂度**:一级汉字通过分块算法快速定位
+- **内存占用小**:仅存储拼音对照数组
-## ����˵��
+## 限制说明
-### ������
+### 多音字
-Ŀǰ��֧�ֶ������������жϣ�������ȡ���ö�����
+目前不支持多音字上下文判断,多音字取常用读音:
```csharp
-PinYin.Get('��') // "Zhong"������ "Chong"��
-PinYin.Get("����") // "ChongQing"���������
-PinYin.Get("��Ҫ") // "ZhongYao"�������ö�����
+PinYin.Get('重') // "Zhong"(而非 "Chong")
+PinYin.Get("重庆") // "ChongQing"(特殊处理)
+PinYin.Get("重要") // "ZhongYao"(按常用读音)
```
-### ��Ƨ��
+### 生僻字
-���� GB2312 ��Χ����Ƨ�ֿ�����ת����
+超出 GB2312 范围的生僻字可能无法转换:
```csharp
-PinYin.Get('?') // "?"����ʶ��ԭ�����أ�
+PinYin.Get('?') // "?"(无法识别,原样返回)
```
-### ������
+### 繁体字
-��֧�ַ�����ת������Ҫ��ת���壺
+不支持繁体字转换,需要先转简体:
```csharp
-PinYin.Get('��') // "��"����ʶ��
-PinYin.Get('��') // "Guo"������������
+PinYin.Get('國') // "國"(无法识别)
+PinYin.Get('国') // "Guo"(简体正常)
```
-## ���ʵ��
+## 最佳实践
-### 1. Ԥ����ƴ���ֶ�
+### 1. 预处理拼音字段
```csharp
-// �Ƽ������ʱԤ�ȼ���ƴ��
+// 推荐:入库时预先计算拼音
user.NamePinyin = PinYin.Get(user.Name);
user.NameFirst = PinYin.GetFirst(user.Name);
db.Save(user);
-// ���Ƽ���ÿ�β�ѯʱʵʱ����
+// 不推荐:每次查询时实时计算
var users = db.Users.Where(u => PinYin.GetFirst(u.Name) == "ZS");
```
-### 2. �����������
+### 2. 组合搜索策略
```csharp
-// �Ƽ���ͬʱ֧��ԭ�ĺ�ƴ������
+// 推荐:同时支持原文和拼音搜索
public List<User> Search(String keyword)
{
return users.Where(u =>
@@ -372,10 +372,10 @@ public List<User> Search(String keyword)
}
```
-### 3. ���泣��ת��
+### 3. 缓存常用转换
```csharp
-// ���ڸ�Ƶת���Ĵʻ㣬�ɿ��ǻ���
+// 对于高频转换的词汇,可考虑缓存
private static readonly ConcurrentDictionary<String, String> _cache = new();
public static String GetCached(String str)
@@ -384,7 +384,7 @@ public static String GetCached(String str)
}
```
-## �������
+## 相关链接
-- [�ַ�����չ StringHelper](string_helper-�ַ�����չStringHelper.md)
-- [����ת�� Utility](utility-����ת��Utility.md)
+- [字符串扩展 StringHelper](string_helper-字符串扩展StringHelper.md)
+- [类型转换 Utility](utility-类型转换Utility.md)
diff --git "a/Doc/\346\217\222\344\273\266\346\241\206\346\236\266IPlugin.md" "b/Doc/\346\217\222\344\273\266\346\241\206\346\236\266IPlugin.md"
index f6f2de3..40e8b05 100644
--- "a/Doc/\346\217\222\344\273\266\346\241\206\346\236\266IPlugin.md"
+++ "b/Doc/\346\217\222\344\273\266\346\241\206\346\236\266IPlugin.md"
@@ -1,91 +1,91 @@
-# ������ IPlugin
+# 插件框架 IPlugin
-## ����
+## 概述
-`IPlugin` �� NewLife.Core �е�ͨ�ò���ӿڣ���� `PluginManager` ��������������Կ��ٹ���һ����ͨ�õIJ��ϵͳ��֧�ֲ�����֡����ء���ʼ������Դ�ͷŵ������������ڹ�����
+`IPlugin` 是 NewLife.Core 中的通用插件接口,配合 `PluginManager` 插件管理器,可以快速构建一个简单通用的插件系统。支持插件发现、加载、初始化和资源释放等完整生命周期管理。
-**�����ռ�**��`NewLife.Model`
-**�ĵ���ַ**��https://newlifex.com/core/plugin
+**命名空间**:`NewLife.Model`
+**文档地址**:https://newlifex.com/core/plugin
-## ��������
+## 核心特性
-- **�Զ�����**��ɨ������Զ����� `IPlugin` ʵ��
-- **����ʶ��**��ͨ�� `PluginAttribute` ��Dz����������
-- **����ע��**��֧�ִ� `IServiceProvider` ʵ�������
-- **��������**��֧�ֳ�ʼ�������ٻص�
-- **��������**�������صķ���˳���ͷ���Դ
+- **自动发现**:扫描程序集自动发现 `IPlugin` 实现
+- **宿主识别**:通过 `PluginAttribute` 标记插件所属宿主
+- **依赖注入**:支持从 `IServiceProvider` 实例化插件
+- **生命周期**:支持初始化和销毁回调
+- **倒序销毁**:按加载的反向顺序释放资源
-## ���ٿ�ʼ
+## 快速开始
-### ������
+### 定义插件
```csharp
using NewLife.Model;
-// ���ʵ��
-[Plugin("MyApp")] // ���֧�ֵ�����
+// 插件实现
+[Plugin("MyApp")] // 标记支持的宿主
public class MyPlugin : IPlugin
{
public Boolean Init(String? identity, IServiceProvider provider)
{
- if (identity != "MyApp") return false; // ��Ŀ������
+ if (identity != "MyApp") return false; // 非目标宿主
- Console.WriteLine("MyPlugin ��ʼ���ɹ�");
+ Console.WriteLine("MyPlugin 初始化成功");
return true;
}
}
```
-### ���ز��
+### 加载插件
```csharp
using NewLife.Model;
-// �������������
+// 创建插件管理器
var manager = new PluginManager
{
Identity = "MyApp",
Provider = ObjectContainer.Provider
};
-// ���ز���ʼ�����
+// 加载并初始化插件
manager.Load();
manager.Init();
-// ʹ�ò��
+// 使用插件
foreach (var plugin in manager.Plugins)
{
- Console.WriteLine($"�Ѽ��ز��: {plugin.GetType().Name}");
+ Console.WriteLine($"已加载插件: {plugin.GetType().Name}");
}
-// �ͷ���Դ
+// 释放资源
manager.Dispose();
```
-## API �ο�
+## API 参考
-### IPlugin �ӿ�
+### IPlugin 接口
```csharp
public interface IPlugin
{
- /// <summary>��ʼ��</summary>
- /// <param name="identity">���������ʶ</param>
- /// <param name="provider">�����ṩ��</param>
- /// <returns>���س�ʼ���Ƿ�ɹ�</returns>
+ /// <summary>初始化</summary>
+ /// <param name="identity">插件宿主标识</param>
+ /// <param name="provider">服务提供者</param>
+ /// <returns>返回初始化是否成功</returns>
Boolean Init(String? identity, IServiceProvider provider);
}
```
-**����˵��**��
-- `identity`��������ʶ�����ڲ���ж��Ƿ�ΪĿ������
-- `provider`�������ṩ�ߣ����ڻ�ȡ��������
+**参数说明**:
+- `identity`:宿主标识,用于插件判断是否为目标宿主
+- `provider`:服务提供者,用于获取依赖服务
-**����ֵ**��
-- `true`����ʼ���ɹ��������ò��
-- `false`����Ŀ���������ʼ��ʧ�ܣ��Ƴ��ò��
+**返回值**:
+- `true`:初始化成功,保留该插件
+- `false`:非目标宿主或初始化失败,移除该插件
-### PluginAttribute ����
+### PluginAttribute 特性
```csharp
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
@@ -95,129 +95,129 @@ public class PluginAttribute : Attribute
}
```
-���ڱ�Dz��֧�ֵ�������ʶ��
+用于标记插件支持的宿主标识。
-**ʾ��**��
+**示例**:
```csharp
-// ֧�ֵ�������
+// 支持单个宿主
[Plugin("WebServer")]
public class WebPlugin : IPlugin { }
-// ֧�ֶ������
+// 支持多个宿主
[Plugin("WebServer")]
[Plugin("ApiServer")]
public class MultiHostPlugin : IPlugin { }
```
-### PluginManager ��
+### PluginManager 类
-#### ����
+#### 属性
```csharp
-/// <summary>������ʶ</summary>
+/// <summary>宿主标识</summary>
public String? Identity { get; set; }
-/// <summary>���������ṩ��</summary>
+/// <summary>宿主服务提供者</summary>
public IServiceProvider? Provider { get; set; }
-/// <summary>�������</summary>
+/// <summary>插件集合</summary>
public IPlugin[]? Plugins { get; set; }
-/// <summary>��־�ṩ��</summary>
+/// <summary>日志提供者</summary>
public ILog Log { get; set; }
```
-#### Load - ���ز��
+#### Load - 加载插件
```csharp
public void Load()
```
-ɨ�����г�������ʵ�� `IPlugin` �ӿڵ����͡�
+扫描所有程序集,加载实现 `IPlugin` 接口的类型。
-**���ع���**��
-1. ɨ�������Ѽ��صij���
-2. ����ʵ�� `IPlugin` �ķdz�����
-3. ��� `PluginAttribute`�����˷ǵ�ǰ�����IJ��
-4. ͨ�������ṩ����ʵ����
+**加载规则**:
+1. 扫描所有已加载的程序集
+2. 查找实现 `IPlugin` 的非抽象类
+3. 检查 `PluginAttribute`,过滤非当前宿主的插件
+4. 通过服务提供者或反射实例化
-#### Init - ��ʼ�����
+#### Init - 初始化插件
```csharp
public void Init()
```
-���ε���ÿ������� `Init` �������Ƴ���ʼ��ʧ�ܵIJ����
+依次调用每个插件的 `Init` 方法,移除初始化失败的插件。
-#### LoadPlugins - ��ȡ�������
+#### LoadPlugins - 获取插件类型
```csharp
public IEnumerable<Type> LoadPlugins()
```
-����ȡ������ͣ���ʵ��������������Ҫ�Զ���ʵ�������ij�����
+仅获取插件类型,不实例化。适用于需要自定义实例化逻辑的场景。
-## �����������
+## 插件生命周期
```
-1. �������� PluginManager
-2. ���� Load() - ���ֲ�ʵ�������
-3. ���� Init() - ��ʼ�����
-4. ���������...
-5. ���� Dispose() - �������ٲ��
+1. 宿主创建 PluginManager
+2. 调用 Load() - 发现并实例化插件
+3. 调用 Init() - 初始化插件
+4. 插件运行期...
+5. 调用 Dispose() - 倒序销毁插件
```
-### ��������ʾ��
+### 生命周期示例
```csharp
public class LifecyclePlugin : IPlugin, IDisposable
{
private ILogger? _logger;
- // ���캯�����������ز��ʱ����
+ // 构造函数:宿主加载插件时调用
public LifecyclePlugin()
{
- Console.WriteLine("1. ���캯��������");
+ Console.WriteLine("1. 构造函数被调用");
}
- // ��ʼ�������������������
+ // 初始化:宿主准备就绪后调用
public Boolean Init(String? identity, IServiceProvider provider)
{
- Console.WriteLine("2. Init ������");
+ Console.WriteLine("2. Init 被调用");
- // ��ȡ����
+ // 获取依赖
_logger = provider.GetService<ILogger>();
- _logger?.Info("�����ʼ��");
+ _logger?.Info("插件初始化");
return true;
}
- // ���٣������ͷ�ʱ����
+ // 销毁:宿主释放时调用
public void Dispose()
{
- Console.WriteLine("3. Dispose ������");
- _logger?.Info("�������");
+ Console.WriteLine("3. Dispose 被调用");
+ _logger?.Info("插件销毁");
}
}
```
-## ʹ�ó���
+## 使用场景
-### 1. ������չ���
+### 1. 功能扩展插件
```csharp
-// ������չ��ӿ�
+// 定义扩展点接口
public interface IDataProcessor
{
String Name { get; }
void Process(Object data);
}
-// ���ʵ��
+// 插件实现
[Plugin("DataPipeline")]
public class JsonProcessor : IPlugin, IDataProcessor
{
- public String Name => "JSON������";
+ public String Name => "JSON处理器";
public Boolean Init(String? identity, IServiceProvider provider)
{
@@ -227,11 +227,11 @@ public class JsonProcessor : IPlugin, IDataProcessor
public void Process(Object data)
{
var json = data.ToJson();
- Console.WriteLine($"����JSON: {json}");
+ Console.WriteLine($"处理JSON: {json}");
}
}
-// ����ʹ��
+// 宿主使用
var manager = new PluginManager { Identity = "DataPipeline" };
manager.Load();
manager.Init();
@@ -242,7 +242,7 @@ foreach (var plugin in manager.Plugins.OfType<IDataProcessor>())
}
```
-### 2. �¼��������
+### 2. 事件监听插件
```csharp
public interface IEventListener
@@ -263,11 +263,11 @@ public class LoggingPlugin : IPlugin, IEventListener
public void OnEvent(String eventName, Object? args)
{
- _log?.Info($"�¼�: {eventName}, ����: {args}");
+ _log?.Info($"事件: {eventName}, 参数: {args}");
}
}
-// �¼��ַ�
+// 事件分发
public class EventDispatcher
{
private readonly IEventListener[] _listeners;
@@ -287,10 +287,10 @@ public class EventDispatcher
}
```
-### 3. ģ�黯Ӧ��
+### 3. 模块化应用
```csharp
-// ģ��ӿ�
+// 模块接口
public interface IModule
{
String Name { get; }
@@ -299,11 +299,11 @@ public interface IModule
void Stop();
}
-// �û�ģ��
+// 用户模块
[Plugin("MainApp")]
public class UserModule : IPlugin, IModule, IDisposable
{
- public String Name => "�û�ģ��";
+ public String Name => "用户模块";
public Boolean Init(String? identity, IServiceProvider provider)
{
@@ -318,18 +318,18 @@ public class UserModule : IPlugin, IModule, IDisposable
public void Start()
{
- XTrace.WriteLine($"{Name} ������");
+ XTrace.WriteLine($"{Name} 已启动");
}
public void Stop()
{
- XTrace.WriteLine($"{Name} ��ֹͣ");
+ XTrace.WriteLine($"{Name} 已停止");
}
public void Dispose() => Stop();
}
-// ������
+// 主程序
class Program
{
static void Main()
@@ -345,19 +345,19 @@ class Program
manager.Load();
manager.Init();
- // �����
+ // 配置模块
foreach (var module in manager.Plugins.OfType<IModule>())
{
module.Configure(ioc);
}
- // �����
+ // 启动模块
foreach (var module in manager.Plugins.OfType<IModule>())
{
module.Start();
}
- Console.WriteLine("��������˳�...");
+ Console.WriteLine("按任意键退出...");
Console.ReadKey();
manager.Dispose();
@@ -365,7 +365,7 @@ class Program
}
```
-### 4. ���Ŀ¼����
+### 4. 插件目录加载
```csharp
public class PluginLoader
@@ -374,7 +374,7 @@ public class PluginLoader
{
if (!Directory.Exists(path)) return;
- // ���ز��Ŀ¼�µ����� DLL
+ // 加载插件目录下的所有 DLL
foreach (var file in Directory.GetFiles(path, "*.dll"))
{
try
@@ -389,34 +389,34 @@ public class PluginLoader
}
}
-// ʹ��
+// 使用
var loader = new PluginLoader();
loader.LoadFromDirectory("plugins");
var manager = new PluginManager { Identity = "MyApp" };
-manager.Load(); // �ᷢ���¼��صij����еIJ��
+manager.Load(); // 会发现新加载的程序集中的插件
manager.Init();
```
-## ���ʵ��
+## 最佳实践
-### 1. ����ӿ����
+### 1. 插件接口设计
```csharp
-// ������������չ��ӿ�
+// 定义清晰的扩展点接口
public interface IPlugin
{
Boolean Init(String? identity, IServiceProvider provider);
}
-// ���ܽӿ������ӿڷ���
+// 功能接口与插件接口分离
public interface IDataExporter
{
String Format { get; }
Byte[] Export(Object data);
}
-// ���ͬʱʵ�������ӿ�
+// 插件同时实现两个接口
[Plugin("ExportSystem")]
public class ExcelExporter : IPlugin, IDataExporter
{
@@ -428,7 +428,7 @@ public class ExcelExporter : IPlugin, IDataExporter
}
```
-### 2. ����ע��
+### 2. 依赖注入
```csharp
[Plugin("MyApp")]
@@ -439,13 +439,13 @@ public class DatabasePlugin : IPlugin
public Boolean Init(String? identity, IServiceProvider provider)
{
- // ��������ȡ����
+ // 从容器获取依赖
_connection = provider.GetService<IDbConnection>();
_logger = provider.GetService<ILogger>();
if (_connection == null)
{
- _logger?.Error("δ�ҵ����ݿ�����");
+ _logger?.Error("未找到数据库连接");
return false;
}
@@ -454,7 +454,7 @@ public class DatabasePlugin : IPlugin
}
```
-### 3. ������
+### 3. 错误处理
```csharp
[Plugin("MyApp")]
@@ -464,19 +464,19 @@ public class SafePlugin : IPlugin
{
try
{
- // ��ʼ����
+ // 初始化逻辑
return true;
}
catch (Exception ex)
{
XTrace.WriteException(ex);
- return false; // ���� false �������׳��쳣
+ return false; // 返回 false 而不是抛出异常
}
}
}
```
-### 4. ��Դ�ͷ�
+### 4. 资源释放
```csharp
[Plugin("MyApp")]
@@ -501,8 +501,8 @@ public class ResourcePlugin : IPlugin, IDisposable
}
```
-## �������
+## 相关链接
-- [�������� ObjectContainer](object_container-��������ObjectContainer.md)
-- [������չ Reflect](reflect-������չReflect.md)
-- [������Ӧ������ Host](host-������Ӧ������Host.md)
+- [对象容器 ObjectContainer](object_container-对象容器ObjectContainer.md)
+- [反射扩展 Reflect](reflect-反射扩展Reflect.md)
+- [轻量级应用主机 Host](host-轻量级应用主机Host.md)
diff --git "a/Doc/\346\225\260\346\215\256\346\211\251\345\261\225IOHelper.md" "b/Doc/\346\225\260\346\215\256\346\211\251\345\261\225IOHelper.md"
index 57243bd..7ce816f 100644
--- "a/Doc/\346\225\260\346\215\256\346\211\251\345\261\225IOHelper.md"
+++ "b/Doc/\346\225\260\346\215\256\346\211\251\345\261\225IOHelper.md"
@@ -1,47 +1,47 @@
-# ������չ IOHelper
+# 数据扩展 IOHelper
-## ����
+## 概述
-`IOHelper` �� NewLife.Core �е� IO ���������࣬�ṩ��Ч���������������ֽ�����ת����ѹ����ѹ������ת���ȹ��ܡ���� .NET 6+ �� `Stream.Read` ����仯�����˼����Դ�����ȷ�������п�ܰ汾����Ϊһ�¡�
+`IOHelper` 是 NewLife.Core 中的 IO 操作工具类,提供高效的数据流操作、字节数组转换、压缩解压、编码转换等功能。针对 .NET 6+ 的 `Stream.Read` 语义变化进行了兼容性处理,确保在所有框架版本上行为一致。
-**�����ռ�**��`NewLife`
-**�ĵ���ַ**��https://newlifex.com/core/io_helper
+**命名空间**:`NewLife`
+**文档地址**:https://newlifex.com/core/io_helper
-## ��������
+## 核心特性
-- **��ȷ��ȡ**��`ReadExactly` ȷ����ȡָ���ֽ�������� .NET 6+ ���ֶ�ȡ����
-- **ѹ����ѹ**��֧�� Deflate �� GZip �����㷨
-- **�ֽ���ת��**��֧�ִ��/С���ֽ���ת��
-- **ʮ�����Ʊ���**����Ч��ʮ�������ַ���ת��
-- **�䳤����**��֧�� 7-bit �����ѹ��������д
+- **精确读取**:`ReadExactly` 确保读取指定字节数,解决 .NET 6+ 部分读取问题
+- **压缩解压**:支持 Deflate 和 GZip 两种算法
+- **字节序转换**:支持大端/小端字节序转换
+- **十六进制编码**:高效的十六进制字符串转换
+- **变长整数**:支持 7-bit 编码的压缩整数读写
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife;
-// �ֽ�����תʮ�������ַ���
+// 字节数组转十六进制字符串
var hex = new Byte[] { 0x12, 0xAB, 0xCD }.ToHex(); // "12ABCD"
-// ʮ�������ַ���ת�ֽ�����
+// 十六进制字符串转字节数组
var data = "12ABCD".ToHex(); // [0x12, 0xAB, 0xCD]
-// Base64 �����
+// Base64 编解码
var base64 = data.ToBase64();
var bytes = base64.ToBase64();
-// ѹ������
+// 压缩数据
var compressed = data.Compress();
var decompressed = compressed.Decompress();
-// ��ת�ַ���
+// 流转字符串
using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Hello"));
var str = stream.ToStr(); // "Hello"
```
-## API �ο�
+## API 参考
-### ��������
+### 属性配置
#### MaxSafeArraySize
@@ -49,17 +49,17 @@ var str = stream.ToStr(); // "Hello"
public static Int32 MaxSafeArraySize { get; set; } = 1024 * 1024;
```
-���ȫ�����С�������ô�Сʱ����ȡ���ݲ�����ǿ��ʧ�ܡ�
+最大安全数组大小。超过该大小时,读取数据操作将强制失败。
-**��;**�����������ã���������������ʱ��ȡ�������鵼��Ӧ�ñ�����
+**用途**:保护性设置,避免解码错误数据时读取超大数组导致应用崩溃。
-**ʾ��**��
+**示例**:
```csharp
-// ��Ҫ������Ͷ���������ʱ���ʵ��ſ�
+// 需要解码大型二进制数据时,适当放宽
IOHelper.MaxSafeArraySize = 10 * 1024 * 1024; // 10MB
```
-### ��������ȡ
+### 数据流读取
#### ReadExactly
@@ -68,19 +68,19 @@ public static Int32 ReadExactly(this Stream stream, Byte[] buffer, Int32 offset,
public static Byte[] ReadExactly(this Stream stream, Int64 count)
```
-��ȷ��ȡָ���ֽ����������ݲ������׳� `EndOfStreamException`��
+精确读取指定字节数。若数据不足则抛出 `EndOfStreamException`。
-**����**��.NET 6 ��ʼ��`Stream.Read` ���ܷ��ز������ݣ�partial read����������ȷ����ȡ�������ݡ�
+**背景**:.NET 6 开始,`Stream.Read` 可能返回部分数据(partial read),本方法确保读取完整数据。
-**ʾ��**��
+**示例**:
```csharp
using var fs = File.OpenRead("data.bin");
-// ��ȡ�̶����ȵ�Э��ͷ
+// 读取固定长度的协议头
var header = new Byte[16];
fs.ReadExactly(header, 0, 16);
-// ��ȡ������������
+// 读取并返回新数组
var data = fs.ReadExactly(1024);
```
@@ -90,21 +90,21 @@ var data = fs.ReadExactly(1024);
public static Int32 ReadAtLeast(this Stream stream, Byte[] buffer, Int32 offset, Int32 count, Int32 minimumBytes, Boolean throwOnEndOfStream = true)
```
-��ȡ����ָ���ֽ�����������ȡ���൫������ `count`��
+读取至少指定字节数,允许读取更多但不超过 `count`。
-**����˵��**��
-- `minimumBytes`��������Ҫ��ȡ���ֽ���
-- `throwOnEndOfStream`�����ݲ���ʱ�Ƿ��׳��쳣
+**参数说明**:
+- `minimumBytes`:最少需要读取的字节数
+- `throwOnEndOfStream`:数据不足时是否抛出异常
-**ʾ��**��
+**示例**:
```csharp
var buffer = new Byte[1024];
-// ���ٶ�ȡ 100 �ֽڣ���� 1024 �ֽ�
+// 至少读取 100 字节,最多 1024 字节
var read = stream.ReadAtLeast(buffer, 0, 1024, 100, throwOnEndOfStream: false);
if (read < 100)
{
- Console.WriteLine("���ݲ���");
+ Console.WriteLine("数据不足");
}
```
@@ -114,21 +114,21 @@ if (read < 100)
public static Byte[] ReadBytes(this Stream stream, Int64 length)
```
-�����ж�ȡָ�����ȵ��ֽ����顣
+从流中读取指定长度的字节数组。
-**����˵��**��
-- `length`��Ҫ��ȡ���ֽ�����-1 ��ʾ��ȡ����ĩβ
+**参数说明**:
+- `length`:要读取的字节数,-1 表示读取到流末尾
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡָ������
+// 读取指定长度
var data = stream.ReadBytes(1024);
-// ��ȡȫ��ʣ������
+// 读取全部剩余数据
var all = stream.ReadBytes(-1);
```
-### �������
+### 数据流写入
#### Write
@@ -136,9 +136,9 @@ var all = stream.ReadBytes(-1);
public static Stream Write(this Stream des, params Byte[] src)
```
-���ֽ�����д����������
+将字节数组写入数据流。
-**ʾ��**��
+**示例**:
```csharp
using var ms = new MemoryStream();
ms.Write(new Byte[] { 1, 2, 3 });
@@ -152,23 +152,23 @@ public static Stream WriteArray(this Stream des, params Byte[] src)
public static Byte[] ReadArray(this Stream des)
```
-д��/��ȡ������ǰ���ֽ����飨ʹ�� 7-bit ����������Ϊ���ȣ���
+写入/读取带长度前缀的字节数组(使用 7-bit 编码整数作为长度)。
-**ʾ��**��
+**示例**:
```csharp
using var ms = new MemoryStream();
-// д�������ǰ������
+// 写入带长度前缀的数据
ms.WriteArray(new Byte[] { 1, 2, 3, 4, 5 });
-// ��ȡ
+// 读取
ms.Position = 0;
var data = ms.ReadArray(); // [1, 2, 3, 4, 5]
```
-### ѹ����ѹ
+### 压缩解压
-#### Compress / Decompress��Deflate��
+#### Compress / Decompress(Deflate)
```csharp
public static Stream Compress(this Stream inStream, Stream? outStream = null)
@@ -177,16 +177,16 @@ public static Byte[] Compress(this Byte[] data)
public static Byte[] Decompress(this Byte[] data)
```
-ʹ�� Deflate �㷨ѹ��/��ѹ���ݡ�
+使用 Deflate 算法压缩/解压数据。
-**ʾ��**��
+**示例**:
```csharp
-// ѹ���ֽ�����
+// 压缩字节数组
var data = Encoding.UTF8.GetBytes("Hello World!");
var compressed = data.Compress();
var decompressed = compressed.Decompress();
-// ѹ��������
+// 压缩数据流
using var input = new MemoryStream(data);
using var output = new MemoryStream();
input.Compress(output);
@@ -201,16 +201,16 @@ public static Byte[] CompressGZip(this Byte[] data)
public static Byte[] DecompressGZip(this Byte[] data)
```
-ʹ�� GZip �㷨ѹ��/��ѹ���ݡ�GZip ��ʽ�����ļ�ͷ��Ϣ�������Ը��á�
+使用 GZip 算法压缩/解压数据。GZip 格式包含文件头信息,兼容性更好。
-**ʾ��**��
+**示例**:
```csharp
var data = File.ReadAllBytes("large-file.txt");
var gzipped = data.CompressGZip();
File.WriteAllBytes("large-file.txt.gz", gzipped);
```
-### �ֽ���ת��
+### 字节序转换
#### ToUInt16 / ToUInt32 / ToUInt64
@@ -220,15 +220,15 @@ public static UInt32 ToUInt32(this Byte[] data, Int32 offset = 0, Boolean isLitt
public static UInt64 ToUInt64(this Byte[] data, Int32 offset = 0, Boolean isLittleEndian = true)
```
-���ֽ������ȡ������֧�ִ��/С���ֽ���
+从字节数组读取整数,支持大端/小端字节序。
-**ʾ��**��
+**示例**:
```csharp
var data = new Byte[] { 0x01, 0x00, 0x00, 0x00 };
-// С����Ĭ�ϣ�
+// 小端序(默认)
var value1 = data.ToUInt32(); // 1
-// �����
+// 大端序
var value2 = data.ToUInt32(isLittleEndian: false); // 16777216
```
@@ -238,18 +238,18 @@ var value2 = data.ToUInt32(isLittleEndian: false); // 16777216
public static Byte[] GetBytes(this Int16 value, Boolean isLittleEndian = true)
public static Byte[] GetBytes(this Int32 value, Boolean isLittleEndian = true)
public static Byte[] GetBytes(this Int64 value, Boolean isLittleEndian = true)
-// ... ��������
+// ... 更多重载
```
-������ת��Ϊ�ֽ����顣
+将整数转换为字节数组。
-**ʾ��**��
+**示例**:
```csharp
-var bytes1 = 12345.GetBytes(); // ����
-var bytes2 = 12345.GetBytes(isLittleEndian: false); // �����
+var bytes1 = 12345.GetBytes(); // 小端序
+var bytes2 = 12345.GetBytes(isLittleEndian: false); // 大端序
```
-### ʮ�����Ʊ���
+### 十六进制编码
#### ToHex
@@ -258,40 +258,40 @@ public static String ToHex(this Byte[] data, Int32 offset = 0, Int32 count = -1)
public static String ToHex(this Byte[] data, String? separate, Int32 lineSize = 0)
```
-���ֽ�����ת��Ϊʮ�������ַ�����
+将字节数组转换为十六进制字符串。
-**ʾ��**��
+**示例**:
```csharp
var data = new Byte[] { 0x12, 0xAB, 0xCD, 0xEF };
-// ����ת��
+// 基本转换
data.ToHex() // "12ABCDEF"
-// ���ָ���
+// 带分隔符
data.ToHex("-") // "12-AB-CD-EF"
data.ToHex(" ") // "12 AB CD EF"
-// ������ʾ
+// 分行显示
var largeData = new Byte[32];
-largeData.ToHex(" ", lineSize: 16) // ÿ 16 �ֽ�һ��
+largeData.ToHex(" ", lineSize: 16) // 每 16 字节一行
```
-#### ToHex���ַ���ת�ֽ����飩
+#### ToHex(字符串转字节数组)
```csharp
public static Byte[] ToHex(this String? data)
```
-��ʮ�������ַ���ת��Ϊ�ֽ����顣
+将十六进制字符串转换为字节数组。
-**ʾ��**��
+**示例**:
```csharp
"12ABCDEF".ToHex() // [0x12, 0xAB, 0xCD, 0xEF]
-"12-AB-CD-EF".ToHex() // [0x12, 0xAB, 0xCD, 0xEF]���Զ����Էָ�����
+"12-AB-CD-EF".ToHex() // [0x12, 0xAB, 0xCD, 0xEF](自动忽略分隔符)
"12 AB CD EF".ToHex() // [0x12, 0xAB, 0xCD, 0xEF]
```
-### Base64 ����
+### Base64 编码
#### ToBase64
@@ -300,19 +300,19 @@ public static String ToBase64(this Byte[] data)
public static Byte[] ToBase64(this String? data)
```
-Base64 ����롣
+Base64 编解码。
-**ʾ��**��
+**示例**:
```csharp
-// ����
+// 编码
var data = Encoding.UTF8.GetBytes("Hello");
var base64 = data.ToBase64(); // "SGVsbG8="
-// ����
+// 解码
var bytes = base64.ToBase64(); // [72, 101, 108, 108, 111]
```
-### �ַ���ת��
+### 字符串转换
#### ToStr
@@ -321,20 +321,20 @@ public static String ToStr(this Stream stream, Encoding? encoding = null)
public static String ToStr(this Byte[] buf, Encoding? encoding = null, Int32 offset = 0, Int32 count = -1)
```
-�������ֽ�����ת��Ϊ�ַ������Զ����� BOM��
+将流或字节数组转换为字符串,自动处理 BOM。
-**ʾ��**��
+**示例**:
```csharp
-// ��ת�ַ���
+// 流转字符串
using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Hello"));
var str = stream.ToStr(); // "Hello"
-// �ֽ�����ת�ַ���
-var data = Encoding.UTF8.GetBytes("����");
-var text = data.ToStr(Encoding.UTF8); // "����"
+// 字节数组转字符串
+var data = Encoding.UTF8.GetBytes("世界");
+var text = data.ToStr(Encoding.UTF8); // "世界"
```
-### �䳤��������
+### 变长整数编码
#### WriteEncodedInt / ReadEncodedInt
@@ -343,31 +343,31 @@ public static Stream WriteEncodedInt(this Stream stream, Int32 value)
public static Int32 ReadEncodedInt(this Stream stream)
```
-ʹ�� 7-bit �����д�䳤������Сֵռ�ø����ֽڡ�
+使用 7-bit 编码读写变长整数,小值占用更少字节。
-**�������**��
-- 0-127��1 �ֽ�
-- 128-16383��2 �ֽ�
-- 16384-2097151��3 �ֽ�
-- �Դ�����
+**编码规则**:
+- 0-127:1 字节
+- 128-16383:2 字节
+- 16384-2097151:3 字节
+- 以此类推
-**ʾ��**��
+**示例**:
```csharp
using var ms = new MemoryStream();
-// д��Сֵֻ�� 1 �ֽ�
-ms.WriteEncodedInt(100); // 1 �ֽ�
+// 写入小值只需 1 字节
+ms.WriteEncodedInt(100); // 1 字节
-// д���ֵ��Ҫ�����ֽ�
-ms.WriteEncodedInt(10000); // 2 �ֽ�
+// 写入大值需要更多字节
+ms.WriteEncodedInt(10000); // 2 字节
-// ��ȡ
+// 读取
ms.Position = 0;
var v1 = ms.ReadEncodedInt(); // 100
var v2 = ms.ReadEncodedInt(); // 10000
```
-### ʱ���д
+### 时间读写
#### WriteDateTime / ReadDateTime
@@ -376,9 +376,9 @@ public static Stream WriteDateTime(this Stream stream, DateTime dt)
public static DateTime ReadDateTime(this Stream stream)
```
-�� Unix ʱ������룩��ʽ��дʱ�䣬4 �ֽڴ洢��
+以 Unix 时间戳(秒)格式读写时间,4 字节存储。
-**ʾ��**��
+**示例**:
```csharp
using var ms = new MemoryStream();
@@ -388,7 +388,7 @@ ms.Position = 0;
var dt = ms.ReadDateTime();
```
-### �ֽ��������
+### 字节数组操作
#### ReadBytes
@@ -396,13 +396,13 @@ var dt = ms.ReadDateTime();
public static Byte[] ReadBytes(this Byte[] src, Int32 offset, Int32 count)
```
-���ֽ������и���ָ����Χ�����ݡ�
+从字节数组中复制指定范围的数据。
-**ʾ��**��
+**示例**:
```csharp
var data = new Byte[] { 1, 2, 3, 4, 5 };
var part = data.ReadBytes(1, 3); // [2, 3, 4]
-var rest = data.ReadBytes(2, -1); // [3, 4, 5]��-1 ��ʾ��ĩβ��
+var rest = data.ReadBytes(2, -1); // [3, 4, 5](-1 表示到末尾)
```
#### Write
@@ -411,48 +411,48 @@ var rest = data.ReadBytes(2, -1); // [3, 4, 5]
public static Int32 Write(this Byte[] dst, Int32 dstOffset, Byte[] src, Int32 srcOffset = 0, Int32 count = -1)
```
-���ֽ�����д�����ݡ�
+向字节数组写入数据。
-**ʾ��**��
+**示例**:
```csharp
var buffer = new Byte[10];
var data = new Byte[] { 1, 2, 3 };
-var written = buffer.Write(0, data); // д�� 3 �ֽ�
+var written = buffer.Write(0, data); // 写入 3 字节
```
-#### CopyTo��ָ�����ȣ�
+#### CopyTo(指定长度)
```csharp
public static void CopyTo(this Stream source, Stream destination, Int64 length, Int32 bufferSize)
```
-��Դ������ָ���������ݵ�Ŀ������
+从源流复制指定长度数据到目标流。
-**ʾ��**��
+**示例**:
```csharp
using var source = File.OpenRead("large-file.bin");
using var dest = File.Create("part.bin");
-// ֻ����ǰ 1MB
+// 只复制前 1MB
source.CopyTo(dest, 1024 * 1024, bufferSize: 81920);
```
-## ʹ�ó���
+## 使用场景
-### 1. ���������
+### 1. 网络协议解析
```csharp
public class ProtocolParser
{
public Message Parse(Stream stream)
{
- // ��ȡ�̶����ȵ�Э��ͷ
+ // 读取固定长度的协议头
var header = stream.ReadExactly(8);
var magic = header.ToUInt32(0);
var length = header.ToUInt32(4);
- // ��ȡ��Ϣ��
+ // 读取消息体
var body = stream.ReadExactly(length);
return new Message { Header = header, Body = body };
@@ -460,7 +460,7 @@ public class ProtocolParser
}
```
-### 2. ���������л�
+### 2. 二进制序列化
```csharp
public class BinarySerializer
@@ -470,7 +470,7 @@ public class BinarySerializer
var json = JsonSerializer.Serialize(obj);
var data = Encoding.UTF8.GetBytes(json);
- // д�볤�Ⱥ�����
+ // 写入长度和数据
stream.WriteArray(data);
}
@@ -483,20 +483,20 @@ public class BinarySerializer
}
```
-### 3. ����ѹ������
+### 3. 数据压缩传输
```csharp
public class CompressedTransport
{
public Byte[] Send(Byte[] data)
{
- // ѹ������
+ // 压缩数据
var compressed = data.CompressGZip();
- // �����������[ѹ����־][ԭʼ����][ѹ������]
+ // 构建传输包:[压缩标志][原始长度][压缩数据]
using var ms = new MemoryStream();
- ms.WriteByte(1); // ѹ����־
- ms.WriteEncodedInt(data.Length); // ԭʼ����
+ ms.WriteByte(1); // 压缩标志
+ ms.WriteEncodedInt(data.Length); // 原始长度
ms.Write(compressed);
return ms.ToArray();
@@ -514,49 +514,49 @@ public class CompressedTransport
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ʹ�� ReadExactly ��� Read
+### 1. 使用 ReadExactly 替代 Read
```csharp
-// �Ƽ���ȷ����ȡ��������
+// 推荐:确保读取完整数据
var data = stream.ReadExactly(100);
-// ���Ƽ�������ֻ��ȡ��������
+// 不推荐:可能只读取部分数据
var buffer = new Byte[100];
-stream.Read(buffer, 0, 100); // .NET 6+ ���ܷ���С�� 100
+stream.Read(buffer, 0, 100); // .NET 6+ 可能返回小于 100
```
-### 2. ע���ֽ���
+### 2. 注意字节序
```csharp
-// ������ϵͳ����ʱע���ֽ���
-// ����Э��ͨ��ʹ�ô����
+// 与其他系统交互时注意字节序
+// 网络协议通常使用大端序
var networkValue = data.ToUInt32(isLittleEndian: false);
-// ���ش洢ͨ��ʹ��С����x86/x64 Ĭ�ϣ�
+// 本地存储通常使用小端序(x86/x64 默认)
var localValue = data.ToUInt32();
```
-### 3. ʹ�ö���ؼ����ڴ����
+### 3. 使用对象池减少内存分配
```csharp
using NewLife.Collections;
-// ʹ���ڴ�����
+// 使用内存流池
var ms = Pool.MemoryStream.Get();
try
{
- // ʹ����...
+ // 使用流...
}
finally
{
- ms.Return(true); // �黹�����
+ ms.Return(true); // 归还并清空
}
```
-## �������
+## 相关链接
-- [·����չ PathHelper](path_helper-·����չPathHelper.md)
-- [��ȫ��չ SecurityHelper](security_helper-��ȫ��չSecurityHelper.md)
-- [���ݰ� IPacket](packet-���ݰ�IPacket.md)
+- [路径扩展 PathHelper](path_helper-路径扩展PathHelper.md)
+- [安全扩展 SecurityHelper](security_helper-安全扩展SecurityHelper.md)
+- [数据包 IPacket](packet-数据包IPacket.md)
diff --git "a/Doc/\346\225\260\346\215\256\351\233\206DbTable.md" "b/Doc/\346\225\260\346\215\256\351\233\206DbTable.md"
index 731916e..a8c5e43 100644
--- "a/Doc/\346\225\260\346\215\256\351\233\206DbTable.md"
+++ "b/Doc/\346\225\260\346\215\256\351\233\206DbTable.md"
@@ -1,31 +1,31 @@
-# DbTable ʹ���ֲ�
+# DbTable 使用手册
-`NewLife.Data.DbTable` ��һ�����������ڴ����ݱ������ڳ��ء��У��ֶΣ�+ �У���¼�����ṹ�����ݡ�
+`NewLife.Data.DbTable` 是一个轻量级的内存数据表,用于承载“列(字段)+ 行(记录)”结构的数据。
-������
+适用场景:
-- DAL ��ѯ��ѽ�������浽�ڴ棬֧�ֶ�α�����ɸѡ��ת��
-- �ڲ����� `DataTable` ������½��п�ƽ̨���ݽ���
-- �����ݶ�дΪ�����ƣ���Ч/��ѹ������Json��Xml��Csv
-- �ڱ�������ģ���б�֮����ӳ��
+- DAL 查询后把结果集缓存到内存,支持多次遍历、筛选、转换
+- 在不依赖 `DataTable` 的情况下进行跨平台数据交换
+- 将数据读写为二进制(高效/可压缩)、Json、Xml、Csv
+- 在表数据与模型列表之间做映射
-- �����ռ䣺`NewLife.Data`
-- ������ͣ�`DbTable`��`DbRow`
+- 命名空间:`NewLife.Data`
+- 相关类型:`DbTable`、`DbRow`
-�ĵ���վ�㣩��https://newlifex.com/core/dbtable
+文档(站点):https://newlifex.com/core/dbtable
---
-## 1. ���ݽṹ
+## 1. 数据结构
-`DbTable` �ĺ������IJ�����ɣ�
+`DbTable` 的核心由四部分组成:
-- `Columns`����������
-- `Types`�����������飨�� `Columns` һһ��Ӧ��
-- `Rows`���м��ϣ�ÿ���� `Object?[]`���� `Columns/Types` ���룩
-- `Total`������������ȡ/д�������ʱ��ʹ�ã�
+- `Columns`:列名数组
+- `Types`:列类型数组(与 `Columns` 一一对应)
+- `Rows`:行集合(每行是 `Object?[]`,与 `Columns/Types` 对齐)
+- `Total`:总行数(读取/写入二进制时会使用)
-ʾ����
+示例:
```csharp
var dt = new DbTable
@@ -41,16 +41,16 @@ var dt = new DbTable
};
```
-ע�⣺
+注意:
-- ͨ�� `Rows[i].Length == Columns.Length`
-- �����ƶ�д���� `Types`������ʼ���� `Columns` ͬ������
+- 通常 `Rows[i].Length == Columns.Length`
+- 二进制读写依赖 `Types`,建议始终与 `Columns` 同步设置
---
-## 2. �����ݿ��ȡ��`IDataReader` / `DbDataReader`��
+## 2. 从数据库读取(`IDataReader` / `DbDataReader`)
-### 2.1 ͬ����ȡ
+### 2.1 同步读取
```csharp
using var cmd = connection.CreateCommand();
@@ -61,15 +61,15 @@ using var dr = cmd.ExecuteReader();
var table = new DbTable();
table.Read(dr);
-Console.WriteLine(table); // DbTable[����][����]
+Console.WriteLine(table); // DbTable[列数][行数]
```
-`Read(dr)` ���Զ����ã�
+`Read(dr)` 会自动调用:
-- `ReadHeader(dr)`����ȡ�������ֶ�����
-- `ReadData(dr)`�����ж�ȡ����� `Rows/Total`
+- `ReadHeader(dr)`:读取列名与字段类型
+- `ReadData(dr)`:逐行读取并填充 `Rows/Total`
-### 2.2 �첽��ȡ
+### 2.2 异步读取
```csharp
await using var cmd = connection.CreateCommand();
@@ -81,59 +81,59 @@ var table = new DbTable();
await table.ReadAsync(dr);
```
-������ڲ�ʹ�� `ConfigureAwait(false)`��
+库代码内部使用 `ConfigureAwait(false)`。
-### 2.3 ָ���ֶ�ӳ�䣨`fields`��
+### 2.3 指定字段映射(`fields`)
-`ReadData`/`ReadDataAsync` ֧�ִ��� `fields`�����ڽ���Ŀ���� i��ӳ�䵽��ȡ���ġ�Դ�� fields[i]����
+`ReadData`/`ReadDataAsync` 支持传入 `fields`,用于将“目标列 i”映射到读取器的“源列 fields[i]”。
```csharp
-// Ŀ���У�Id, Name
+// 目标列:Id, Name
table.Columns = ["Id", "Name"];
table.Types = [typeof(Int32), typeof(String)];
-// �Ӷ�ȡ���ĵ� 2 �к͵� 0 ��ȡֵ
+// 从读取器的第 2 列和第 0 列取值
table.ReadData(dr, fields: [2, 0]);
```
-#### `DBNull` Ĭ��ֵ����
+#### `DBNull` 默认值策略
-��ȡ�� `DBNull.Value` ʱ��`DbTable` �ᰴ��������д��Ĭ��ֵ��������ֵ `0`��`false`��`DateTime.MinValue`���������DZ��� `null`��
+读取到 `DBNull.Value` 时,`DbTable` 会按该列类型写入默认值(例如数值 `0`、`false`、`DateTime.MinValue`),而不是保留 `null`。
---
-## 3. �� `DataTable` ��ת
+## 3. 与 `DataTable` 互转
-### 3.1 �� `DataTable` ��ȡ
+### 3.1 从 `DataTable` 读取
```csharp
var table = new DbTable();
var count = table.Read(dataTable);
```
-- ��� `dataTable.Columns` ��ȡ����������
-- ���ÿ�е� `ItemArray` ��Ϊ `Object?[]` ���� `Rows`
+- 会从 `dataTable.Columns` 获取列名与类型
+- 会把每行的 `ItemArray` 作为 `Object?[]` 加入 `Rows`
-### 3.2 д�뵽 `DataTable`
+### 3.2 写入到 `DataTable`
```csharp
DataTable dataTable = table.ToDataTable();
-// ���������
+// 或复用已有对象
var dt2 = table.Write(existing);
```
---
-## 4. ���������л����Ƽ���
+## 4. 二进制序列化(推荐)
-`DbTable` ���ö����ƶ�д���ʺϴ�����������/���̣�
+`DbTable` 内置二进制读写,适合大数据量传输/落盘:
-- ͷ�������� + �汾 + ��� + �ж��� + ����
-- �����壺��������˳����ֵд��
-- `*.gz` �ļ����Զ�ѹ��/��ѹ
+- 头部:幻数 + 版本 + 标记 + 列定义 + 行数
+- 数据体:按列类型顺序逐值写入
+- `*.gz` 文件可自动压缩/解压
-### 4.1 д��/��ȡ `Stream`
+### 4.1 写入/读取 `Stream`
```csharp
using var ms = new MemoryStream();
@@ -144,15 +144,15 @@ var table2 = new DbTable();
table2.Read(ms);
```
-### 4.2 תΪ���ݰ� `IPacket`
+### 4.2 转为数据包 `IPacket`
-�ʺ����紫�䣨ͷ��Ԥ�� 8 �ֽڣ������ϲ�Э���Ӱ�ͷ����
+适合网络传输(头部预留 8 字节,方便上层协议追加包头):
```csharp
IPacket pk = table.ToPacket();
```
-### 4.3 ����/�����ļ�
+### 4.3 保存/加载文件
```csharp
table.SaveFile("data.db");
@@ -162,22 +162,22 @@ var t2 = new DbTable();
t2.LoadFile("data.db");
```
-### 4.4 ���������߶��ߴ���������һ���Լ���ȫ�� `Rows`��
+### 4.4 迭代器:边读边处理(避免一次性加载全部 `Rows`)
```csharp
var table = new DbTable();
foreach (var row in table.LoadRows("data.db.gz"))
{
- // row �� Object?[]
+ // row 是 Object?[]
}
```
-˵����
+说明:
-- `LoadRows` ���ȶ�ȡͷ�����ٸ��� `Total` ������ȡ����
-- �� `Total == 0` ���ļ��ǿգ����� `rows = -1` һֱ����������
+- `LoadRows` 会先读取头部,再根据 `Total` 决定读取行数
+- 若 `Total == 0` 且文件非空,将以 `rows = -1` 一直读到流结束
-### 4.5 ���������ߴ�����д��
+### 4.5 迭代器:边处理边写入
```csharp
var table = new DbTable
@@ -190,61 +190,61 @@ IEnumerable<Object?[]> rows = GetRows();
var count = table.SaveRows("data.db.gz", rows);
```
-ָ����ӳ��˳��
+指定列映射顺序:
```csharp
-var fields = new[] { 1, 0 }; // Ŀ���� i ��ӦԴ row �� fields[i]
+var fields = new[] { 1, 0 }; // 目标列 i 对应源 row 的 fields[i]
var count = table.SaveRows("data.db", rows, fields);
```
-- `fields[i] == -1` ��ʾд���ֵ����Ŀ��������д�룩
+- `fields[i] == -1` 表示写入空值(按目标列类型写入)
---
-## 5. Json ���л�
+## 5. Json 序列化
-`ToJson()` ����ת��Ϊ���ֵ����顱�����л���
+`ToJson()` 会先转换为“字典数组”再序列化:
```csharp
String json = table.ToJson(indented: true);
```
-�ֵ�������ʽ��
+字典数组形式:
```csharp
IList<IDictionary<String, Object?>> list = table.ToDictionary();
```
-- �ֵ� key Ϊ���� `Columns[i]`
-- value Ϊ��ֵ `row[i]`
+- 字典 key 为列名 `Columns[i]`
+- value 为行值 `row[i]`
---
-## 6. Xml ���л�
+## 6. Xml 序列化
-`GetXml()` ������ `DbTable` ���ڵ㣬�ڲ�ÿ���� `Table` �ڵ㣬ÿ��������Ϊ�ӽڵ㡣
+`GetXml()` 会生成 `DbTable` 根节点,内部每行是 `Table` 节点,每个列名作为子节点。
```csharp
String xml = table.GetXml();
```
-д�뵽���� `Stream`��
+写入到任意 `Stream`:
```csharp
await table.WriteXml(stream);
```
-����д����ԣ�
+类型写入策略:
-- `Boolean`��д�벼��ֵ
-- `DateTime`��� `DateTimeOffset`
-- `DateTimeOffset`��ֱ��д��
-- `IFormattable`������ʽд���ַ���
-- ������`ToString()`
+- `Boolean`:写入布尔值
+- `DateTime`:写入 `DateTimeOffset`
+- `DateTimeOffset`:直接写入
+- `IFormattable`:按格式写入字符串
+- 其他:`ToString()`
---
-## 7. Csv ���л�
+## 7. Csv 序列化
```csharp
table.SaveCsv("data.csv");
@@ -253,14 +253,14 @@ var t2 = new DbTable();
t2.LoadCsv("data.csv");
```
-- `SaveCsv`����д��ͷ�������У���д��������
-- `LoadCsv`����һ����Ϊ `Columns`��������Ϊ������
+- `SaveCsv`:先写表头(列名行)再写入所有行
+- `LoadCsv`:第一行作为 `Columns`,其余作为数据行
---
-## 8. ģ�ͻ�ת
+## 8. 模型互转
-### 8.1 ģ���б�д�� `DbTable`
+### 8.1 模型列表写入 `DbTable`
```csharp
var list = new[]
@@ -273,31 +273,31 @@ var table = new DbTable();
table.WriteModels(list);
```
-����
+规则:
-- ѡ�� `T` �Ĺ�������
-- �������������������ԡ���`IsBaseType()`��
-- �� `Columns` Ϊ�����Զ����������� `Columns/Types`
-- ��ֵͨ�������ȡ����ģ��ʵ�� `IModel`���������������� `model[name]`
+- 选择 `T` 的公共属性
+- 仅保留“基础类型属性”(`IsBaseType()`)
+- 若 `Columns` 为空则自动按属性生成 `Columns/Types`
+- 行值通过反射读取;若模型实现 `IModel`,则优先用索引器 `model[name]`
-### 8.2 `DbTable` ��ȡΪģ���б�
+### 8.2 `DbTable` 读取为模型列表
```csharp
IEnumerable<User> users = table.ReadModels<User>();
-// ��ָ�� Type
+// 或指定 Type
IEnumerable<Object> objs = table.ReadModels(typeof(User));
```
-ӳ�����
+映射规则:
-- ʹ�� `SerialHelper.GetName(PropertyInfo)` ��ȡ�ֶ�����֧�����Ա�����
-- ������Сд������ƥ������
-- ��Ŀ��ģ��ʵ�� `IModel`����ͨ����������ֵ������ͨ������ `SetValue`
+- 使用 `SerialHelper.GetName(PropertyInfo)` 获取字段名(支持特性别名)
+- 列名大小写不敏感匹配属性
+- 若目标模型实现 `IModel`,则通过索引器赋值,否则通过反射 `SetValue`
---
-## 9. ��ݶ�ȡ�������л�ȡֵ��
+## 9. 便捷读取(按行列获取值)
```csharp
var name = table.Get<String>(row: 0, name: "Name");
@@ -308,22 +308,22 @@ if (table.TryGet<Int32>(1, "Id", out var id))
}
```
-- `GetColumn(name)` ֧�ֺ��Դ�Сд
+- `GetColumn(name)` 支持忽略大小写
---
-## 10. ö���� `DbRow`
+## 10. 枚举与 `DbRow`
-`DbTable` ʵ�� `IEnumerable<DbRow>`����ֱ�� `foreach`��
+`DbTable` 实现 `IEnumerable<DbRow>`,可直接 `foreach`:
```csharp
foreach (var row in table)
{
- // row �� DbRow
+ // row 是 DbRow
}
```
-��ȡָ���У�
+获取指定行:
```csharp
var row = table.GetRow(0);
@@ -331,12 +331,12 @@ var row = table.GetRow(0);
---
-## 11. ��¡
+## 11. 克隆
-`Clone()` Ϊdz������
+`Clone()` 为浅拷贝:
-- `Columns/Types` ����������
-- `Rows` ʹ�� `ToList()` �������б����������������Թ���
+- `Columns/Types` 拷贝为新数组
+- `Rows` 使用 `ToList()` 创建新列表,但行数组引用仍共享
```csharp
var copy = table.Clone();
@@ -344,20 +344,20 @@ var copy = table.Clone();
---
-## 12. ��������
+## 12. 常见问题
-### 12.1 Ϊʲô `DBNull` ����Ĭ��ֵ��
+### 12.1 为什么 `DBNull` 会变成默认值?
-���� `DbTable.ReadData(...)` �ļȶ����ԣ������������Ĭ��ֵ�����ں���ֱ������ֵ/����/ʱ����㡣
+这是 `DbTable.ReadData(...)` 的既定策略:按列类型填充默认值,便于后续直接做数值/布尔/时间计算。
-��ҵ����Ҫ���� `null` ���壬�����ϲ����д�����
+若业务需要保留 `null` 语义,请在上层自行处理。
-### 12.2 �����Ƹ�ʽ�Ƿ��ȶ���
+### 12.2 二进制格式是否稳定?
-�����Ƹ�ʽ�����汾�ţ���ǰ�汾Ϊ `3`������ȡʱ�������߰汾���׳� `InvalidDataException`��
+二进制格式包含版本号(当前版本为 `3`)。读取时遇到更高版本会抛出 `InvalidDataException`。
-### 12.3 ��������������ô�ã�
+### 12.3 大数据量建议怎么用?
-- ��ȡ������ `LoadRows`/`ReadRows` ��������
-- д�룺���� `SaveRows`/`WriteRows` ����д��
-- ���紫�䣺ʹ�� `ToPacket()`
+- 读取:优先 `LoadRows`/`ReadRows` 迭代消费
+- 写入:优先 `SaveRows`/`WriteRows` 迭代写入
+- 网络传输:使用 `ToPacket()`
diff --git "a/Doc/\346\227\245\345\277\227ILog.md" "b/Doc/\346\227\245\345\277\227ILog.md"
index 4ba0a44..6bb5154 100644
--- "a/Doc/\346\227\245\345\277\227ILog.md"
+++ "b/Doc/\346\227\245\345\277\227ILog.md"
@@ -1,177 +1,177 @@
-# ��־ILog
+# 日志ILog
-## ����
+## 概述
-`NewLife.Log.ILog` �� NewLife.Core �ĺ�����־�ӿڣ��ṩͳһ����־��¼�淶��NewLife ȫϵ�������ʹ�øýӿڼ�¼��־��
+`NewLife.Log.ILog` 是 NewLife.Core 的核心日志接口,提供统一的日志记录规范。NewLife 全系列组件均使用该接口记录日志。
-ͨ����̬�� `XTrace` ���Է����ʹ����־���ܣ�֧�֣�
-- �ļ���־��Ĭ�ϣ�
-- ����̨��־
-- ������־
-- �Զ�����־ʵ��
+通过静态类 `XTrace` 可以方便地使用日志功能,支持:
+- 文件日志(默认)
+- 控制台日志
+- 网络日志
+- 自定义日志实现
-**�����ռ�**: `NewLife.Log`
-**Դ��**: [NewLife.Core/Log/ILog.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Log/ILog.cs)
-**�ĵ�**: https://newlifex.com/core/log
+**命名空间**: `NewLife.Log`
+**源码**: [NewLife.Core/Log/ILog.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Log/ILog.cs)
+**文档**: https://newlifex.com/core/log
---
-## ��������
+## 快速入门
-### �����÷�
+### 基础用法
```csharp
using NewLife.Log;
-// ��ʽ1��ʹ�� XTrace ��̬�ࣨ�Ƽ���
-XTrace.WriteLine("����һ����Ϣ");
-XTrace.WriteLine("�û�{0}��¼", "admin");
+// 方式1:使用 XTrace 静态类(推荐)
+XTrace.WriteLine("这是一条信息");
+XTrace.WriteLine("用户{0}登录", "admin");
-// ��ʽ2��ֱ��ʹ�� ILog �ӿ�
+// 方式2:直接使用 ILog 接口
ILog log = XTrace.Log;
-log.Info("����һ����Ϣ");
-log.Error("����һ������");
+log.Info("这是一条信息");
+log.Error("这是一条错误");
```
-### ��־����
+### 日志级别
```csharp
-XTrace.Log.Debug("������Ϣ"); // ������־
-XTrace.Log.Info("��ͨ��Ϣ"); // ��Ϣ��־
-XTrace.Log.Warn("������Ϣ"); // ������־
-XTrace.Log.Error("������Ϣ"); // ������־
-XTrace.Log.Fatal("���ش���"); // ���ش�����־
+XTrace.Log.Debug("调试信息"); // 调试日志
+XTrace.Log.Info("普通信息"); // 信息日志
+XTrace.Log.Warn("警告信息"); // 警告日志
+XTrace.Log.Error("错误信息"); // 错误日志
+XTrace.Log.Fatal("严重错误"); // 严重错误日志
```
-### ����쳣
+### 输出异常
```csharp
try
{
- // ҵ�����
+ // 业务代码
}
catch (Exception ex)
{
- XTrace.WriteException(ex); // ����쳣��ջ
+ XTrace.WriteException(ex); // 输出异常堆栈
}
```
---
-## ILog �ӿ�
+## ILog 接口
```csharp
public interface ILog
{
- /// <summary>д��־</summary>
+ /// <summary>写日志</summary>
void Write(LogLevel level, String format, params Object?[] args);
- /// <summary>������־</summary>
+ /// <summary>调试日志</summary>
void Debug(String format, params Object?[] args);
- /// <summary>��Ϣ��־</summary>
+ /// <summary>信息日志</summary>
void Info(String format, params Object?[] args);
- /// <summary>������־</summary>
+ /// <summary>警告日志</summary>
void Warn(String format, params Object?[] args);
- /// <summary>������־</summary>
+ /// <summary>错误日志</summary>
void Error(String format, params Object?[] args);
- /// <summary>���ش�����־</summary>
+ /// <summary>严重错误日志</summary>
void Fatal(String format, params Object?[] args);
- /// <summary>�Ƿ�������־��Ϊfalseʱ������κ���־</summary>
+ /// <summary>是否启用日志。为false时不输出任何日志</summary>
Boolean Enable { get; set; }
- /// <summary>��־�ȼ���ֻ������ڵ��ڸü������־��Ĭ��Info</summary>
+ /// <summary>日志等级,只输出大于等于该级别的日志,默认Info</summary>
LogLevel Level { get; set; }
}
```
-### ��־���� LogLevel
+### 日志级别 LogLevel
```csharp
public enum LogLevel
{
- /// <summary>�ر���־</summary>
+ /// <summary>关闭日志</summary>
Off = 0,
- /// <summary>���ش�����Ӧ�ó����˳�</summary>
+ /// <summary>严重错误。导致应用程序退出</summary>
Fatal = 1,
- /// <summary>����Ӱ�칦�����У���Ҫ��������</summary>
+ /// <summary>错误。影响功能运行,需要立即处理</summary>
Error = 2,
- /// <summary>���档��Ӱ�칦�ܣ�����Ҫ��ע</summary>
+ /// <summary>警告。不影响功能,但需要关注</summary>
Warn = 3,
- /// <summary>��Ϣ��������־��Ϣ</summary>
+ /// <summary>信息。常规日志信息</summary>
Info = 4,
- /// <summary>���ԡ�������־����������Ӧ�ر�</summary>
+ /// <summary>调试。调试日志,生产环境应关闭</summary>
Debug = 5,
- /// <summary>ȫ��</summary>
+ /// <summary>全部</summary>
All = 6
}
```
---
-## XTrace ��̬��
+## XTrace 静态类
-`XTrace` ����־����Ҫʹ����ڣ��ṩ��ݵľ�̬������
+`XTrace` 是日志的主要使用入口,提供便捷的静态方法。
-### ��������
+### 基础方法
```csharp
-// �����Ϣ��־
-XTrace.WriteLine("��Ϣ");
-XTrace.WriteLine("�û�{0}��{1}��¼", "admin", DateTime.Now);
+// 输出信息日志
+XTrace.WriteLine("消息");
+XTrace.WriteLine("用户{0}在{1}登录", "admin", DateTime.Now);
-// ����쳣
+// 输出异常
XTrace.WriteException(ex);
```
-### �ؼ�����
+### 关键属性
```csharp
-// ��ȡ��������־ʵ��
-ILog log = XTrace.Log; // Ĭ��Ϊ�ļ���־
-XTrace.Log = new ConsoleLog(); // �л�Ϊ����̨��־
+// 获取或设置日志实现
+ILog log = XTrace.Log; // 默认为文件日志
+XTrace.Log = new ConsoleLog(); // 切换为控制台日志
-// �Ƿ����ģʽ
-XTrace.Debug = true; // �������ԣ����Debug������־
+// 是否调试模式
+XTrace.Debug = true; // 开启调试,输出Debug级别日志
-// ��־·��
-XTrace.LogPath = "Logs"; // ������־�ļ���
+// 日志路径
+XTrace.LogPath = "Logs"; // 设置日志文件夹
```
---
-## Ĭ���ļ���־
+## 默认文件日志
-NewLife Ĭ��ʹ�� `TextFileLog`������־������ı��ļ���
+NewLife 默认使用 `TextFileLog`,将日志输出到文本文件。
-### ����
+### 特性
-- �Զ������ڷָ���־�ļ����� `2025-01-07.log`��
-- �첽д�룬������ҵ���߳�
-- �Զ����ݺ���������־
-- ֧��������־·��������ļ���С��
+- 自动按日期分割日志文件(如 `2025-01-07.log`)
+- 异步写入,不阻塞业务线程
+- 自动备份和清理旧日志
+- 支持配置日志路径、最大文件大小等
-### ����
+### 配置
-�� `NewLife.config` �� `appsettings.json` �����ã�
+在 `NewLife.config` 或 `appsettings.json` 中配置:
```xml
<!-- NewLife.config -->
<Config>
<Setting>
- <LogPath>Logs</LogPath> <!-- ��־·�� -->
- <LogLevel>Info</LogLevel> <!-- ��־���� -->
- <LogFileFormat>{0:yyyy-MM-dd}.log</LogFileFormat> <!-- �ļ�������ʽ -->
+ <LogPath>Logs</LogPath> <!-- 日志路径 -->
+ <LogLevel>Info</LogLevel> <!-- 日志级别 -->
+ <LogFileFormat>{0:yyyy-MM-dd}.log</LogFileFormat> <!-- 文件命名格式 -->
</Setting>
</Config>
```
@@ -189,112 +189,112 @@ NewLife Ĭ
}
```
-### ��־�ļ�ʾ��
+### 日志文件示例
```
-2025-01-07 10:15:23.456 Info Ӧ�ó�������
-2025-01-07 10:15:24.123 Info �û�admin��¼
-2025-01-07 10:20:15.789 Warn ���ӳ�����
-2025-01-07 10:25:30.456 Error ���ݿ����ӳ�ʱ
-System.TimeoutException: ���ӳ�ʱ
+2025-01-07 10:15:23.456 Info 应用程序启动
+2025-01-07 10:15:24.123 Info 用户admin登录
+2025-01-07 10:20:15.789 Warn 连接池已满
+2025-01-07 10:25:30.456 Error 数据库连接超时
+System.TimeoutException: 连接超时
at MyApp.Database.Query(String sql)
at MyApp.Service.GetData()
```
---
-## ����̨��־
+## 控制台日志
-�ڿ���̨Ӧ���У�����ʹ�� `UseConsole()` ����־���������̨��
+在控制台应用中,可以使用 `UseConsole()` 将日志输出到控制台。
-### ʹ�÷���
+### 使用方法
```csharp
class Program
{
static void Main(String[] args)
{
- // �ض�����־������̨
+ // 重定向日志到控制台
XTrace.UseConsole();
- XTrace.WriteLine("Ӧ�ó�������");
- XTrace.Log.Error("����һ������");
+ XTrace.WriteLine("应用程序启动");
+ XTrace.Log.Error("这是一条错误");
}
}
```
-### ��ɫ���
+### 彩色输出
-����̨��־֧�ֲ�ɫ�������ͬ��־����ʹ�ò�ͬ��ɫ��
-- **Debug**: ��ɫ
-- **Info**: ��ɫ
-- **Warn**: ��ɫ
-- **Error**: ��ɫ
-- **Fatal**: ���ɫ
+控制台日志支持彩色输出,不同日志级别使用不同颜色:
+- **Debug**: 灰色
+- **Info**: 白色
+- **Warn**: 黄色
+- **Error**: 红色
+- **Fatal**: 洋红色
-### ���̲߳�ɫ
+### 多线程彩色
```csharp
-XTrace.UseConsole(useColor: true); // ���ò�ɫ���
+XTrace.UseConsole(useColor: true); // 启用彩色输出
ThreadPool.QueueUserWorkItem(_ =>
{
- XTrace.WriteLine("�߳�1"); // �Զ�ʹ�ò�ͬ��ɫ
+ XTrace.WriteLine("线程1"); // 自动使用不同颜色
});
ThreadPool.QueueUserWorkItem(_ =>
{
- XTrace.WriteLine("�߳�2"); // �Զ�ʹ�ò�ͬ��ɫ
+ XTrace.WriteLine("线程2"); // 自动使用不同颜色
});
```
---
-## ������־
+## 网络日志
-����־ͨ�����緢�͵�Զ����־��������
+将日志通过网络发送到远程日志服务器。
-### ʹ�÷���
+### 使用方法
```csharp
-// ����������־
+// 配置网络日志
XTrace.Log = new NetworkLog("tcp://logserver:514");
-XTrace.WriteLine("������־�ᷢ�͵�Զ�̷�����");
+XTrace.WriteLine("这条日志会发送到远程服务器");
```
-### ����
+### 适用场景
-- ����ʽ��־�ռ�
-- �ֲ�ʽϵͳ��־�ۺ�
-- ������Ӧ����־���
+- 集中式日志收集
+- 分布式系统日志聚合
+- 容器化应用日志输出
---
-## ������־
+## 复合日志
-ͬʱ��������Ŀ�ꡣ
+同时输出到多个目标。
-### ʹ�÷���
+### 使用方法
```csharp
using NewLife.Log;
var compositeLog = new CompositeLog();
-compositeLog.Add(new TextFileLog()); // �ļ���־
-compositeLog.Add(new ConsoleLog()); // ����̨��־
-compositeLog.Add(new NetworkLog("tcp://logserver:514")); // ������־
+compositeLog.Add(new TextFileLog()); // 文件日志
+compositeLog.Add(new ConsoleLog()); // 控制台日志
+compositeLog.Add(new NetworkLog("tcp://logserver:514")); // 网络日志
XTrace.Log = compositeLog;
```
---
-## �Զ�����־
+## 自定义日志
-ʵ�� `ILog` �ӿڴ����Զ�����־��
+实现 `ILog` 接口创建自定义日志。
-### ʾ�������ݿ���־
+### 示例:数据库日志
```csharp
public class DatabaseLog : ILog
@@ -308,7 +308,7 @@ public class DatabaseLog : ILog
var message = args.Length > 0 ? String.Format(format, args) : format;
- // д�����ݿ�
+ // 写入数据库
Database.Insert("Logs", new
{
Level = level.ToString(),
@@ -324,24 +324,24 @@ public class DatabaseLog : ILog
public void Fatal(String format, params Object?[] args) => Write(LogLevel.Fatal, format, args);
}
-// ʹ��
+// 使用
XTrace.Log = new DatabaseLog();
```
---
-## ʹ�ó���
+## 使用场景
-### 1. Ӧ�ó���������־
+### 1. 应用程序启动日志
```csharp
class Program
{
static void Main(String[] args)
{
- XTrace.WriteLine("Ӧ�ó�������");
- XTrace.WriteLine("�汾��{0}", Assembly.GetExecutingAssembly().GetName().Version);
- XTrace.WriteLine("����ʱ��{0}", Runtime.Version);
+ XTrace.WriteLine("应用程序启动");
+ XTrace.WriteLine("版本:{0}", Assembly.GetExecutingAssembly().GetName().Version);
+ XTrace.WriteLine("运行时:{0}", Runtime.Version);
try
{
@@ -350,34 +350,34 @@ class Program
catch (Exception ex)
{
XTrace.WriteException(ex);
- XTrace.Log.Fatal("Ӧ�ó����쳣�˳�");
+ XTrace.Log.Fatal("应用程序异常退出");
}
}
}
```
-### 2. �ӿڵ�����־
+### 2. 接口调用日志
```csharp
public class UserService
{
public void Login(String username, String password)
{
- XTrace.WriteLine("�û�{0}���Ե�¼", username);
+ XTrace.WriteLine("用户{0}尝试登录", username);
if (ValidateUser(username, password))
{
- XTrace.WriteLine("�û�{0}��¼�ɹ�", username);
+ XTrace.WriteLine("用户{0}登录成功", username);
}
else
{
- XTrace.Log.Warn("�û�{0}��¼ʧ�ܣ��������", username);
+ XTrace.Log.Warn("用户{0}登录失败:密码错误", username);
}
}
}
```
-### 3. �쳣����
+### 3. 异常处理
```csharp
try
@@ -387,7 +387,7 @@ try
}
catch (TimeoutException ex)
{
- XTrace.Log.Warn("���ݻ�ȡ��ʱ��{0}", ex.Message);
+ XTrace.Log.Warn("数据获取超时:{0}", ex.Message);
}
catch (Exception ex)
{
@@ -396,106 +396,106 @@ catch (Exception ex)
}
```
-### 4. ������־
+### 4. 调试日志
```csharp
#if DEBUG
-XTrace.Debug = true; // ����������������
+XTrace.Debug = true; // 开发环境开启调试
#endif
-XTrace.Log.Debug("��ʼ�������ݣ�{0}��", data.Length);
+XTrace.Log.Debug("开始处理数据:{0}条", data.Length);
foreach (var item in data)
{
- XTrace.Log.Debug("������Ŀ��{0}", item.Id);
+ XTrace.Log.Debug("处理项目:{0}", item.Id);
ProcessItem(item);
}
-XTrace.Log.Debug("���ݴ������");
+XTrace.Log.Debug("数据处理完成");
```
---
-## ���ʵ��
+## 最佳实践
-### 1. ����ʹ����־����
+### 1. 合理使用日志级别
```csharp
-// Debug��������Ϣ����������Ӧ�ر�
-XTrace.Log.Debug("����ֵ��{0}", value);
+// Debug:调试信息,生产环境应关闭
+XTrace.Log.Debug("变量值:{0}", value);
-// Info��������Ϣ����¼��Ҫ����
-XTrace.Log.Info("�û�{0}��¼", username);
+// Info:常规信息,记录重要操作
+XTrace.Log.Info("用户{0}登录", username);
-// Warn��������Ϣ����Ӱ�칦�ܵ����ע
-XTrace.Log.Warn("���ӳ�ʹ���ʣ�{0}%", usage);
+// Warn:警告信息,不影响功能但需关注
+XTrace.Log.Warn("连接池使用率:{0}%", usage);
-// Error��������Ϣ��Ӱ�칦������
-XTrace.Log.Error("���ݿ�����ʧ�ܣ�{0}", ex.Message);
+// Error:错误信息,影响功能运行
+XTrace.Log.Error("数据库连接失败:{0}", ex.Message);
-// Fatal�����ش�����Ӧ���˳�
-XTrace.Log.Fatal("�����ļ���Ӧ�ó����˳�");
+// Fatal:严重错误,导致应用退出
+XTrace.Log.Fatal("配置文件损坏,应用程序退出");
```
-### 2. ������־��Ϣ����
+### 2. 避免日志信息过多
```csharp
-// ���Ƽ���ѭ���������־
-foreach (var item in items) // 100��������
+// 不推荐:循环中输出日志
+foreach (var item in items) // 100万条数据
{
- XTrace.Log.Debug("������{0}", item); // ����100������־��
+ XTrace.Log.Debug("处理:{0}", item); // 产生100万条日志!
}
-// �Ƽ����������
+// 推荐:汇总输出
var count = 0;
foreach (var item in items)
{
ProcessItem(item);
count++;
}
-XTrace.Log.Info("������ɣ�{0}��", count);
+XTrace.Log.Info("处理完成:{0}条", count);
```
-### 3. ʹ�ýṹ����־
+### 3. 使用结构化日志
```csharp
-// �Ƽ���ʹ��ռλ��
-XTrace.Log.Info("�û�{0}��{1}��¼��IP={2}", username, location, ip);
+// 推荐:使用占位符
+XTrace.Log.Info("用户{0}从{1}登录,IP={2}", username, location, ip);
-// ���Ƽ����ַ���ƴ��
-XTrace.Log.Info("�û�" + username + "��" + location + "��¼��IP=" + ip);
+// 不推荐:字符串拼接
+XTrace.Log.Info("用户" + username + "从" + location + "登录,IP=" + ip);
```
-### 4. ���ܿ���
+### 4. 性能考虑
```csharp
-// �Ƽ������жϼ���
+// 推荐:先判断级别
if (XTrace.Log.Enable && XTrace.Log.Level >= LogLevel.Debug)
{
- var expensiveData = GetExpensiveDebugInfo(); // �������
- XTrace.Log.Debug("������Ϣ��{0}", expensiveData);
+ var expensiveData = GetExpensiveDebugInfo(); // 昂贵操作
+ XTrace.Log.Debug("调试信息:{0}", expensiveData);
}
-// ���Ƽ���ֱ�ӵ���
-XTrace.Log.Debug("������Ϣ��{0}", GetExpensiveDebugInfo()); // ��ʹDebug�ر�Ҳ��ִ��
+// 不推荐:直接调用
+XTrace.Log.Debug("调试信息:{0}", GetExpensiveDebugInfo()); // 即使Debug关闭也会执行
```
---
-## ���ù���
+## 配置管理
-### ͨ����������
+### 通过代码配置
```csharp
-// ������־����
-XTrace.Log.Level = LogLevel.Warn; // ֻ���Warn������
+// 设置日志级别
+XTrace.Log.Level = LogLevel.Warn; // 只输出Warn及以上
-// �ر���־
+// 关闭日志
XTrace.Log.Enable = false;
-// ������־·��
+// 设置日志路径
XTrace.LogPath = "C:\\Logs";
```
-### ͨ�������ļ�
+### 通过配置文件
```xml
<!-- NewLife.config -->
@@ -508,10 +508,10 @@ XTrace.LogPath = "C:\\Logs";
</Config>
```
-### ����ʱ��
+### 运行时修改
```csharp
-// ��ʱ��������
+// 临时开启调试
var oldDebug = XTrace.Debug;
XTrace.Debug = true;
@@ -521,15 +521,15 @@ try
}
finally
{
- XTrace.Debug = oldDebug; // �ָ�����
+ XTrace.Debug = oldDebug; // 恢复设置
}
```
---
-## ȫ���쳣����
+## 全局异常处理
-XTrace �Զ�����δ�����쳣��
+XTrace 自动捕获未处理异常:
```csharp
static XTrace()
@@ -539,30 +539,30 @@ static XTrace()
}
```
-������δ�����쳣ʱ�����Զ�����쳣��־��
+当发生未处理异常时,会自动输出异常日志。
---
-## ��������
+## 常见问题
-### 1. ��ιر���־��
+### 1. 如何关闭日志?
```csharp
-// ��ʽ1���ر���־���
+// 方式1:关闭日志输出
XTrace.Log.Enable = false;
-// ��ʽ2��������־����ΪOff
+// 方式2:设置日志级别为Off
XTrace.Log.Level = LogLevel.Off;
-// ��ʽ3��ʹ�ÿ���־
+// 方式3:使用空日志
XTrace.Log = Logger.Null;
```
-### 2. ��־�ļ������
+### 2. 日志文件在哪里?
-Ĭ����Ӧ�ó����Ŀ¼�� `Logs` �ļ����£��ļ�����ʽΪ `yyyy-MM-dd.log`��
+默认在应用程序根目录的 `Logs` 文件夹下,文件名格式为 `yyyy-MM-dd.log`。
-### 3. �����������Ŀ�ꣿ
+### 3. 如何输出到多个目标?
```csharp
var compositeLog = new CompositeLog();
@@ -571,40 +571,40 @@ compositeLog.Add(new ConsoleLog());
XTrace.Log = compositeLog;
```
-### 4. ��־�ļ�̫����ô�죿
+### 4. 日志文件太大怎么办?
-������־���ݺ��������ԣ�
+配置日志备份和清理策略:
```csharp
var textLog = new TextFileLog();
-textLog.MaxBytes = 10 * 1024 * 1024; // ���10MB
-textLog.Backups = 10; // ����10������
+textLog.MaxBytes = 10 * 1024 * 1024; // 最大10MB
+textLog.Backups = 10; // 保留10个备份
```
-### 5. �����ASP.NET Core��ʹ�ã�
+### 5. 如何在ASP.NET Core中使用?
```csharp
-// Startup.cs �� Program.cs
+// Startup.cs 或 Program.cs
public void Configure(IApplicationBuilder app)
{
- // ��־���Զ���ʼ����ֱ��ʹ��
- XTrace.WriteLine("Ӧ�ó�������");
+ // 日志已自动初始化,直接使用
+ XTrace.WriteLine("应用程序启动");
}
```
---
-## �����
+## 参考资料
-- **�����ĵ�**: https://newlifex.com/core/log
-- **Դ��**: https://github.com/NewLifeX/X/tree/master/NewLife.Core/Log
-- **��·��**: [tracer-��·��ITracer.md](tracer-��·��ITracer.md)
+- **在线文档**: https://newlifex.com/core/log
+- **源码**: https://github.com/NewLifeX/X/tree/master/NewLife.Core/Log
+- **链路追踪**: [tracer-链路追踪ITracer.md](tracer-链路追踪ITracer.md)
---
-## ������־
+## 更新日志
-- **2025-01**: �����ĵ���������ϸʾ��
-- **2024**: ֧�� .NET 9.0
-- **2023**: �Ż��첽д������
-- **2022**: ����������־֧��
-- **2020**: �ع���־�ܹ���ͳһ�ӿ�
+- **2025-01**: 完善文档,补充详细示例
+- **2024**: 支持 .NET 9.0
+- **2023**: 优化异步写入性能
+- **2022**: 增加网络日志支持
+- **2020**: 重构日志架构,统一接口
diff --git "a/Doc/\346\234\272\345\231\250\344\277\241\346\201\257MachineInfo.md" "b/Doc/\346\234\272\345\231\250\344\277\241\346\201\257MachineInfo.md"
index e9217d2..37a11e2 100644
--- "a/Doc/\346\234\272\345\231\250\344\277\241\346\201\257MachineInfo.md"
+++ "b/Doc/\346\234\272\345\231\250\344\277\241\346\201\257MachineInfo.md"
@@ -1,225 +1,225 @@
-# ������ϢMachineInfo
+# 机器信息MachineInfo
-## ����
+## 概述
-`NewLife.MachineInfo` ���ڻ�ȡ������Ӳ����ϵͳ��Ϣ��֧��Windows��Linux��Mac�ȶ��ֲ���ϵͳ��
+`NewLife.MachineInfo` 用于获取机器的硬件和系统信息,支持Windows、Linux、Mac等多种操作系统。
-**��Ҫ����**��
-- ��ȡ����ϵͳ��Ϣ�����ơ��汾��
-- ��ȡӲ����Ϣ��CPU���ڴ桢���̣�
-- ��ȡΨһ��ʶ��UUID��GUID�����кţ�
-- ��ȡ��̬��Ϣ��CPUռ���ʡ��ڴ�ʹ�á������ٶȣ�
+**主要功能**:
+- 获取操作系统信息(名称、版本)
+- 获取硬件信息(CPU、内存、磁盘)
+- 获取唯一标识(UUID、GUID、序列号)
+- 获取动态信息(CPU占用率、内存使用、网络速度)
-**�����ռ�**: `NewLife`
-**Դ��**: [NewLife.Core/Common/MachineInfo.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Common/MachineInfo.cs)
-**�ĵ�**: https://newlifex.com/core/machine_info
+**命名空间**: `NewLife`
+**源码**: [NewLife.Core/Common/MachineInfo.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Common/MachineInfo.cs)
+**文档**: https://newlifex.com/core/machine_info
---
-## ��������
+## 快速入门
-### �����÷�
+### 基础用法
```csharp
using NewLife;
-// ��ȡ��ǰ������Ϣ���״ε��û��ʼ����
+// 获取当前机器信息(首次调用会初始化)
var machine = MachineInfo.GetCurrent();
-Console.WriteLine($"����ϵͳ��{machine.OSName} {machine.OSVersion}");
-Console.WriteLine($"��������{machine.Processor}");
-Console.WriteLine($"�ڴ�������{machine.Memory / 1024 / 1024 / 1024}GB");
-Console.WriteLine($"Ӳ����ʶ��{machine.UUID}");
-Console.WriteLine($"ϵͳ��ʶ��{machine.Guid}");
+Console.WriteLine($"操作系统:{machine.OSName} {machine.OSVersion}");
+Console.WriteLine($"处理器:{machine.Processor}");
+Console.WriteLine($"内存总量:{machine.Memory / 1024 / 1024 / 1024}GB");
+Console.WriteLine($"硬件标识:{machine.UUID}");
+Console.WriteLine($"系统标识:{machine.Guid}");
```
-### �첽��ʼ��
+### 异步初始化
```csharp
-// �첽ע�������Ϣ���Ƽ���Ӧ������ʱ���ã�
+// 异步注册机器信息(推荐在应用启动时调用)
var machine = await MachineInfo.RegisterAsync();
-Console.WriteLine($"CPUռ�ã�{machine.CpuRate:P2}");
-Console.WriteLine($"�����ڴ棺{machine.AvailableMemory / 1024 / 1024}MB");
+Console.WriteLine($"CPU占用:{machine.CpuRate:P2}");
+Console.WriteLine($"可用内存:{machine.AvailableMemory / 1024 / 1024}MB");
```
-### ˢ�¶�̬����
+### 刷新动态数据
```csharp
var machine = MachineInfo.GetCurrent();
-// ˢ�¶�̬���ݣ�CPU���ڴ桢����ȣ�
+// 刷新动态数据(CPU、内存、网络等)
machine.Refresh();
-Console.WriteLine($"CPUռ�ã�{machine.CpuRate:P2}");
-Console.WriteLine($"�����ڴ棺{machine.FreeMemory / 1024 / 1024}MB");
-Console.WriteLine($"�����ٶȣ�{machine.DownlinkSpeed / 1024}KB/s");
-Console.WriteLine($"�ϴ��ٶȣ�{machine.UplinkSpeed / 1024}KB/s");
+Console.WriteLine($"CPU占用:{machine.CpuRate:P2}");
+Console.WriteLine($"空闲内存:{machine.FreeMemory / 1024 / 1024}MB");
+Console.WriteLine($"下载速度:{machine.DownlinkSpeed / 1024}KB/s");
+Console.WriteLine($"上传速度:{machine.UplinkSpeed / 1024}KB/s");
```
---
-## ��������
+## 核心属性
-### ��̬��Ϣ����ʼ���䣩
+### 静态信息(初始化后不变)
-| ���� | ���� | ˵�� | ʾ�� |
+| 属性 | 类型 | 说明 | 示例 |
|-----|------|------|------|
-| `OSName` | String | ����ϵͳ���� | "Windows 11", "Ubuntu 22.04" |
-| `OSVersion` | String | ϵͳ�汾�� | "10.0.22000", "5.15.0" |
-| `Product` | String | ��Ʒ���� | "ThinkPad X1 Carbon" |
-| `Vendor` | String | ������ | "Lenovo", "Dell" |
-| `Processor` | String | �������ͺ� | "Intel Core i7-1165G7" |
-| `UUID` | String | Ӳ��Ψһ��ʶ���������кţ� | "xxxx-xxxx-xxxx" |
-| `Guid` | String | ����Ψһ��ʶ��ϵͳID�� | "xxxx-xxxx-xxxx" |
-| `Serial` | String | ��������к� | "PF2ABCDE" |
-| `Board` | String | ������Ϣ | "20XWCTO1WW" |
-| `DiskID` | String | �������к� | "1234567890" |
-| `Memory` | UInt64 | �ڴ��������ֽڣ� | 17179869184 (16GB) |
-
-### ��̬��Ϣ����Ҫˢ�£�
-
-| ���� | ���� | ˵�� |
+| `OSName` | String | 操作系统名称 | "Windows 11", "Ubuntu 22.04" |
+| `OSVersion` | String | 系统版本号 | "10.0.22000", "5.15.0" |
+| `Product` | String | 产品名称 | "ThinkPad X1 Carbon" |
+| `Vendor` | String | 制造商 | "Lenovo", "Dell" |
+| `Processor` | String | 处理器型号 | "Intel Core i7-1165G7" |
+| `UUID` | String | 硬件唯一标识(主板序列号) | "xxxx-xxxx-xxxx" |
+| `Guid` | String | 软件唯一标识(系统ID) | "xxxx-xxxx-xxxx" |
+| `Serial` | String | 计算机序列号 | "PF2ABCDE" |
+| `Board` | String | 主板信息 | "20XWCTO1WW" |
+| `DiskID` | String | 磁盘序列号 | "1234567890" |
+| `Memory` | UInt64 | 内存总量(字节) | 17179869184 (16GB) |
+
+### 动态信息(需要刷新)
+
+| 属性 | 类型 | 说明 |
|-----|------|------|
-| `AvailableMemory` | UInt64 | �����ڴ棨�ֽڣ� |
-| `FreeMemory` | UInt64 | �����ڴ棨�ֽڣ� |
-| `CpuRate` | Double | CPUռ���ʣ�0-1�� |
-| `UplinkSpeed` | UInt64 | ���������ٶȣ��ֽ�/�룩 |
-| `DownlinkSpeed` | UInt64 | ���������ٶȣ��ֽ�/�룩 |
-| `Temperature` | Double | �¶ȣ��ȣ� |
-| `Battery` | Double | ���ʣ�ࣨ0-1�� |
+| `AvailableMemory` | UInt64 | 可用内存(字节) |
+| `FreeMemory` | UInt64 | 空闲内存(字节) |
+| `CpuRate` | Double | CPU占用率(0-1) |
+| `UplinkSpeed` | UInt64 | 网络上行速度(字节/秒) |
+| `DownlinkSpeed` | UInt64 | 网络下行速度(字节/秒) |
+| `Temperature` | Double | 温度(度) |
+| `Battery` | Double | 电池剩余(0-1) |
---
-## �����
+## 核心方法
-### RegisterAsync - �첽ע��
+### RegisterAsync - 异步注册
```csharp
-/// <summary>�첽ע��һ����ʼ����Ļ�����Ϣʵ��</summary>
+/// <summary>异步注册一个初始化后的机器信息实例</summary>
public static Task<MachineInfo> RegisterAsync()
```
-**�ص�**��
-- �첽ִ�У����������߳�
-- �״ε���ʱ��ʼ��������ֱ�ӷ��ػ�����
-- �Զ����浽�ļ���`machine_info.json`�����ӿ���������ٶ�
-- ע�ᵽ�������� `ObjectContainer`
+**特点**:
+- 异步执行,不阻塞主线程
+- 首次调用时初始化,后续直接返回缓存结果
+- 自动缓存到文件(`machine_info.json`),加快后续启动速度
+- 注册到对象容器 `ObjectContainer`
-**ʾ��**��
+**示例**:
```csharp
-// Ӧ������ʱ�첽ע��
+// 应用启动时异步注册
await MachineInfo.RegisterAsync();
-// ����ֱ��ʹ��
+// 后续直接使用
var machine = MachineInfo.Current;
```
-### GetCurrent - ��ȡ��ǰʵ��
+### GetCurrent - 获取当前实例
```csharp
-/// <summary>��ȡ��ǰ��Ϣ�����δ������ȴ��첽ע����</summary>
+/// <summary>获取当前信息,如果未设置则等待异步注册结果</summary>
public static MachineInfo GetCurrent()
```
-**ʾ��**��
+**示例**:
```csharp
var machine = MachineInfo.GetCurrent();
Console.WriteLine(machine.OSName);
```
-### Refresh - ˢ�¶�̬����
+### Refresh - 刷新动态数据
```csharp
-/// <summary>ˢ�¶�̬���ݣ�CPU���ڴ桢����ȣ�</summary>
+/// <summary>刷新动态数据(CPU、内存、网络等)</summary>
public void Refresh()
```
-**ʾ��**��
+**示例**:
```csharp
var machine = MachineInfo.GetCurrent();
-machine.Refresh(); // ����CPUռ�á��ڴ�ʹ�õ�
+machine.Refresh(); // 更新CPU占用、内存使用等
Console.WriteLine($"CPU: {machine.CpuRate:P}");
```
---
-## Ψһ��ʶ˵��
+## 唯一标识说明
-### UUID��Ӳ����ʶ��
+### UUID(硬件标识)
-- **��Դ**���������к�
-- **�ص�**����Ӳ�������������仯
-- **ע��**������Ʒ�ƣ���ijЩ���ƻ��������ظ�
+- **来源**:主板序列号
+- **特点**:与硬件绑定,更换主板后变化
+- **注意**:部分品牌(如某些白牌机)可能重复
```csharp
-var uuid = machine.UUID; // �� "A1B2C3D4-E5F6-..."
+var uuid = machine.UUID; // 如 "A1B2C3D4-E5F6-..."
```
-### Guid��ϵͳ��ʶ��
+### Guid(系统标识)
-- **��Դ**��
- - Windows��ע��� `MachineGuid`
- - Linux��`/etc/machine-id`
- - Android��`android_id`
-- **�ص�**�������ϵͳ��װ����װϵͳ��仯
-- **ע��**��Ghostϵͳ�����ظ�
+- **来源**:
+ - Windows:注册表 `MachineGuid`
+ - Linux:`/etc/machine-id`
+ - Android:`android_id`
+- **特点**:与操作系统安装绑定,重装系统后变化
+- **注意**:Ghost系统可能重复
```csharp
-var guid = machine.Guid; // �� "B1C2D3E4-F5A6-..."
+var guid = machine.Guid; // 如 "B1C2D3E4-F5A6-..."
```
-### Serial�����кţ�
+### Serial(序列号)
-- **��Դ**����������кţ�BIOS��
-- **�ص�**��Ʒ�ƻ����У���ʼDZ���ǩһ��
-- **ע��**����װ��ͨ��Ϊ��
+- **来源**:计算机序列号(BIOS)
+- **特点**:品牌机独有,与笔记本标签一致
+- **注意**:组装机通常为空
```csharp
-var serial = machine.Serial; // �� "PF2ABCDE"
+var serial = machine.Serial; // 如 "PF2ABCDE"
```
-### DiskID���������кţ�
+### DiskID(磁盘序列号)
-- **��Դ**��ϵͳ�����к�
-- **�ص�**�������Ӳ����
-- **ע��**������Ӳ�̺�仯
+- **来源**:系统盘序列号
+- **特点**:与磁盘硬件绑定
+- **注意**:更换硬盘后变化
---
-## �ڴ���Ϣ���
+## 内存信息详解
-### AvailableMemory�������ڴ棩
+### AvailableMemory(可用内存)
-**�Ƽ�����Ӧ�����ұ����ͼ�ظ澯**
+**推荐用于应用自我保护和监控告警**
-- **Linux**��`MemAvailable`���ں������ɰ�ȫ������ڴ棩
-- **Windows**��`ullAvailPhys`����ǰ���������ڴ棩
+- **Linux**:`MemAvailable`(内核评估可安全分配的内存)
+- **Windows**:`ullAvailPhys`(当前可用物理内存)
```csharp
-if (machine.AvailableMemory < 100 * 1024 * 1024) // ��100MB
+if (machine.AvailableMemory < 100 * 1024 * 1024) // 小于100MB
{
- Console.WriteLine("�ڴ治�㣬�ܾ�������");
+ Console.WriteLine("内存不足,拒绝新任务");
}
```
-### FreeMemory�������ڴ棩
+### FreeMemory(空闲内存)
-**�ʺ����ڼ��չʾ���˹�����**
+**适合用于监控展示和人工分析**
-- **Linux**��`MemFree + Buffers + Cached + SReclaimable - Shmem`
-- **Windows**���� `AvailableMemory` һ��
+- **Linux**:`MemFree + Buffers + Cached + SReclaimable - Shmem`
+- **Windows**:与 `AvailableMemory` 一致
```csharp
-Console.WriteLine($"�����ڴ棺{machine.FreeMemory / 1024 / 1024}MB");
+Console.WriteLine($"空闲内存:{machine.FreeMemory / 1024 / 1024}MB");
```
---
-## ʹ�ó���
+## 使用场景
-### 1. Ӧ�ü��
+### 1. 应用监控
```csharp
var timer = new TimerX(async _ =>
@@ -227,7 +227,7 @@ var timer = new TimerX(async _ =>
var machine = MachineInfo.GetCurrent();
machine.Refresh();
- // �ϱ��������
+ // 上报监控数据
await ReportMetrics(new
{
CpuRate = machine.CpuRate,
@@ -235,10 +235,10 @@ var timer = new TimerX(async _ =>
DownlinkSpeed = machine.DownlinkSpeed,
UplinkSpeed = machine.UplinkSpeed
});
-}, null, 0, 60000); // ÿ�����ϱ�
+}, null, 0, 60000); // 每分钟上报
```
-### 2. �豸ע��
+### 2. 设备注册
```csharp
var machine = await MachineInfo.RegisterAsync();
@@ -256,33 +256,33 @@ var device = new Device
await RegisterDevice(device);
```
-### 3. ��Ȩ��֤
+### 3. 授权验证
```csharp
var machine = MachineInfo.GetCurrent();
-// ����Ӳ����ʶ��֤��Ȩ
+// 基于硬件标识验证授权
if (!IsLicenseValid(machine.UUID))
{
- throw new UnauthorizedAccessException("δ��Ȩ���豸");
+ throw new UnauthorizedAccessException("未授权的设备");
}
```
-### 4. ����Ӧ��Դ����
+### 4. 自适应资源分配
```csharp
var machine = MachineInfo.GetCurrent();
var cpuCount = Environment.ProcessorCount;
var memoryGB = machine.Memory / 1024 / 1024 / 1024;
-// ���ݻ������õ����̳߳ش�С
+// 根据机器配置调整线程池大小
ThreadPool.SetMinThreads(cpuCount * 2, cpuCount * 2);
-// �����ڴ��С������������
-var cacheSize = (Int32)(memoryGB * 0.1 * 1024 * 1024 * 1024); // 10%�ڴ�
+// 根据内存大小调整缓存容量
+var cacheSize = (Int32)(memoryGB * 0.1 * 1024 * 1024 * 1024); // 10%内存
```
-### 5. ���ܸ澯
+### 5. 性能告警
```csharp
var machine = MachineInfo.GetCurrent();
@@ -290,197 +290,197 @@ machine.Refresh();
if (machine.CpuRate > 0.9)
{
- SendAlert("CPUʹ���ʹ��ߣ�" + machine.CpuRate.ToString("P"));
+ SendAlert("CPU使用率过高:" + machine.CpuRate.ToString("P"));
}
if (machine.AvailableMemory < 100 * 1024 * 1024)
{
- SendAlert("�����ڴ治�㣺" + machine.AvailableMemory / 1024 / 1024 + "MB");
+ SendAlert("可用内存不足:" + machine.AvailableMemory / 1024 / 1024 + "MB");
}
```
---
-## ���ʵ��
+## 最佳实践
-### 1. Ӧ������ʱ�첽ע��
+### 1. 应用启动时异步注册
```csharp
class Program
{
static async Task Main(String[] args)
{
- // �첽ע�������Ϣ��������������
+ // 异步注册机器信息(不阻塞启动)
_ = MachineInfo.RegisterAsync();
- // ����Ӧ�ó�ʼ��
+ // 继续应用初始化
await StartApplication();
}
}
```
-### 2. ʹ�õ���ģʽ
+### 2. 使用单例模式
```csharp
-// MachineInfo �ڲ���ʵ�ֵ���
-var machine = MachineInfo.Current; // ʹ����ע���ʵ��
+// MachineInfo 内部已实现单例
+var machine = MachineInfo.Current; // 使用已注册的实例
```
-### 3. ����ˢ�¶�̬����
+### 3. 定期刷新动态数据
```csharp
-// ��ҪƵ��ˢ�£�����������1��
+// 不要频繁刷新,建议间隔至少1秒
var timer = new TimerX(_ =>
{
MachineInfo.Current?.Refresh();
}, null, 0, 1000);
```
-### 4. ���������
+### 4. 利用文件缓存
```csharp
-// ������Ϣ���Զ����浽��
+// 机器信息会自动缓存到:
// - {Temp}/machine_info.json
// - {DataPath}/machine_info.json
-// �´�����ʱ�Զ����ػ��棬�ӿ��ʼ���ٶ�
+// 下次启动时自动加载缓存,加快初始化速度
```
---
-## ��չ����
+## 扩展功能
-### �Զ��������Ϣ�ṩ��
+### 自定义机器信息提供者
```csharp
public class CustomMachineInfo : IMachineInfo
{
public void Init(MachineInfo info)
{
- // �Զ����ʼ����
+ // 自定义初始化逻辑
info["CustomField"] = "CustomValue";
}
public void Refresh(MachineInfo info)
{
- // �Զ���ˢ����
+ // 自定义刷新逻辑
info["Timestamp"] = DateTime.Now;
}
}
-// ע���Զ����ṩ��
+// 注册自定义提供者
MachineInfo.Provider = new CustomMachineInfo();
await MachineInfo.RegisterAsync();
```
-### ʹ����չ����
+### 使用扩展属性
```csharp
var machine = MachineInfo.GetCurrent();
-// ������չ����
+// 设置扩展属性
machine["AppVersion"] = "1.0.0";
machine["DeployTime"] = DateTime.Now;
-// ��ȡ��չ����
+// 获取扩展属性
var version = machine["AppVersion"] as String;
```
---
-## ע������
+## 注意事项
-### 1. �첽��ʼ��
+### 1. 异步初始化
```csharp
-// �Ƽ����첽ע��
+// 推荐:异步注册
await MachineInfo.RegisterAsync();
-// ���Ƽ���ͬ���ȴ�
-var machine = MachineInfo.GetCurrent(); // ��������
+// 不推荐:同步等待
+var machine = MachineInfo.GetCurrent(); // 可能阻塞
```
-### 2. Ȩ��Ҫ��
+### 2. 权限要求
-ijЩ��Ϣ��Ҫ�ض�Ȩ�ޣ�
-- **Windows**����ȡע�����Ҫ����ԱȨ�ޣ����ּ���
-- **Linux**����ȡ `/sys` �� `/proc` ͨ����Ҫ root Ȩ��
-- **����**������ͨ�û����У���ȡʧ��ʱʹ��Ĭ��ֵ
+某些信息需要特定权限:
+- **Windows**:读取注册表需要管理员权限(部分键)
+- **Linux**:读取 `/sys` 和 `/proc` 通常需要 root 权限
+- **建议**:以普通用户运行,读取失败时使用默认值
-### 3. Ψһ��ʶ�����ظ�
+### 3. 唯一标识可能重复
-- **UUID**�����ְ��ƻ�/����������ظ�
-- **Guid**��Ghostϵͳ�����ظ�
-- **����**����϶����ʶ����ΨһID
+- **UUID**:部分白牌机/虚拟机可能重复
+- **Guid**:Ghost系统可能重复
+- **建议**:组合多个标识生成唯一ID
```csharp
var uniqueId = $"{machine.UUID}_{machine.Guid}_{machine.DiskID}".MD5();
```
-### 4. ���ܿ���
+### 4. 性能考虑
-- **��ʼ��**���״�ִ�н�����100-500ms��������ʹ�û���
-- **ˢ��**��ÿ�ε��������ܿ����������Ƶ����
-- **����**����ʱˢ�£���ÿ��һ�Σ�����ʵʱˢ��
+- **初始化**:首次执行较慢(100-500ms),后续使用缓存
+- **刷新**:每次调用有性能开销,避免高频调用
+- **建议**:定时刷新(如每秒一次)而非实时刷新
---
-## ��ƽ̨֧��
+## 跨平台支持
### Windows
-֧�֣�
+支持:
- ? OSName, OSVersion
- ? Processor, Memory
-- ? UUID���������кţ�
-- ? Guid��MachineGuid��
+- ? UUID(主板序列号)
+- ? Guid(MachineGuid)
- ? Serial, Product, Vendor
- ? CpuRate, AvailableMemory
- ? UplinkSpeed, DownlinkSpeed
### Linux
-֧�֣�
+支持:
- ? OSName, OSVersion
- ? Processor, Memory
-- ? UUID��DMI��
-- ? Guid��/etc/machine-id��
+- ? UUID(DMI)
+- ? Guid(/etc/machine-id)
- ? CpuRate, AvailableMemory
- ? UplinkSpeed, DownlinkSpeed
-- ?? Serial, Product�������豸��֧�֣�
+- ?? Serial, Product(部分设备不支持)
### macOS
-֧�֣�
+支持:
- ? OSName, OSVersion
- ? Processor, Memory
-- ? UUID��Hardware UUID��
-- ?? ������Ϣ֧������
+- ? UUID(Hardware UUID)
+- ?? 其他信息支持有限
---
-## ��������
+## 常见问题
-### 1. UUID Ϊʲô�ǿգ�
+### 1. UUID 为什么是空?
-����ԭ��
-- ���������
-- ���ƻ�û���������к�
-- Ȩ����
+可能原因:
+- 虚拟机环境
+- 白牌机没有主板序列号
+- 权限不足
-�����ʹ�� `Guid` ����϶����ʶ��
+解决:使用 `Guid` 或组合多个标识。
-### 2. Guid Ϊ `0-xxxx` ��ʽ��
+### 2. Guid 为 `0-xxxx` 格式?
-��ʾ����ȡϵͳ��ʶ���Զ����ɵ����GUID��
+表示无法读取系统标识,自动生成的随机GUID。
-### 3. ˢ�º����ݲ��䣿
+### 3. 刷新后数据不变?
-��飺
-- �Ƿ���Ȩ��ȡϵͳ��Ϣ
-- ˢ�¼���Ƿ���̣������1�룩
+检查:
+- 是否有权限读取系统信息
+- 刷新间隔是否过短(建议≥1秒)
-### 4. ��λ�ȡ���������ٶȣ�
+### 4. 如何获取所有网卡速度?
```csharp
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
@@ -493,18 +493,18 @@ foreach (var ni in interfaces)
---
-## �����
+## 参考资料
-- **�����ĵ�**: https://newlifex.com/core/machine_info
-- **Դ��**: https://github.com/NewLifeX/X/blob/master/NewLife.Core/Common/MachineInfo.cs
-- **����**: [setting-��������Setting.md](setting-��������Setting.md)
+- **在线文档**: https://newlifex.com/core/machine_info
+- **源码**: https://github.com/NewLifeX/X/blob/master/NewLife.Core/Common/MachineInfo.cs
+- **配置**: [setting-核心配置Setting.md](setting-核心配置Setting.md)
---
-## ������־
+## 更新日志
-- **2025-01**: �����ĵ���������ϸ˵��
-- **2024**: ֧�� .NET 9.0���Ż���ƽ̨֧��
-- **2023**: ���� AvailableMemory �� FreeMemory
-- **2022**: ���������ٶȡ��¶ȡ���صȶ�̬��Ϣ
-- **2020**: ��ʼ�汾��֧�ֻ���Ӳ����Ϣ��ȡ
+- **2025-01**: 完善文档,补充详细说明
+- **2024**: 支持 .NET 9.0,优化跨平台支持
+- **2023**: 区分 AvailableMemory 和 FreeMemory
+- **2022**: 增加网络速度、温度、电池等动态信息
+- **2020**: 初始版本,支持基础硬件信息获取
diff --git "a/Doc/\347\261\273\345\236\213\350\275\254\346\215\242Utility.md" "b/Doc/\347\261\273\345\236\213\350\275\254\346\215\242Utility.md"
index 32b64e3..6f75398 100644
--- "a/Doc/\347\261\273\345\236\213\350\275\254\346\215\242Utility.md"
+++ "b/Doc/\347\261\273\345\236\213\350\275\254\346\215\242Utility.md"
@@ -1,42 +1,42 @@
-# ����ת�� Utility
+# 类型转换 Utility
-## ����
+## 概述
-`Utility` �� NewLife.Core ��������Ĺ����࣬�ṩ��Ч����ȫ������ת����չ����������ת��������֧��Ĭ��ֵ����ת��ʧ��ʱ����Ĭ��ֵ�����׳��쳣����������ճ������е�����ת��������
+`Utility` 是 NewLife.Core 中最基础的工具类,提供高效、安全的类型转换扩展方法。所有转换方法均支持默认值,在转换失败时返回默认值而不抛出异常,极大简化了日常开发中的类型转换操作。
-**�����ռ�**��`NewLife`
-**�ĵ���ַ**��https://newlifex.com/core/utility
+**命名空间**:`NewLife`
+**文档地址**:https://newlifex.com/core/utility
-## ��������
+## 核心特性
-- **��ȫת��**������ת��ʧ��ʱ����Ĭ��ֵ�����׳��쳣
-- **��չ����**��ֱ���ڶ����ϵ��� `.ToInt()`��`.ToDateTime()` ��
-- **������֧��**��֧���ַ�����ȫ���ַ����ֽ����顢ʱ����ȶ�������
-- **������**����Գ�����������Ż������ⲻ��Ҫ���ڴ����
-- **����չ**��ͨ�� `DefaultConvert` ��֧���Զ���ת����
+- **安全转换**:所有转换失败时返回默认值,不抛出异常
+- **扩展方法**:直接在对象上调用 `.ToInt()`、`.ToDateTime()` 等
+- **多类型支持**:支持字符串、全角字符、字节数组、时间戳等多种输入
+- **高性能**:针对常见场景深度优化,避免不必要的内存分配
+- **可扩展**:通过 `DefaultConvert` 类支持自定义转换逻辑
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife;
-// �ַ���ת����
+// 字符串转整数
var num = "123".ToInt(); // 123
-var num2 = "abc".ToInt(-1); // -1��ת��ʧ�ܷ���Ĭ��ֵ��
+var num2 = "abc".ToInt(-1); // -1(转换失败返回默认值)
-// �ַ���תʱ��
+// 字符串转时间
var dt = "2024-01-15".ToDateTime();
var dt2 = "invalid".ToDateTime(); // DateTime.MinValue
-// ����ת����
+// 对象转布尔
var flag = "true".ToBoolean(); // true
var flag2 = "1".ToBoolean(); // true
var flag3 = "yes".ToBoolean(); // true
```
-## API �ο�
+## API 参考
-### ����ת��
+### 整数转换
#### ToInt
@@ -44,32 +44,32 @@ var flag3 = "yes".ToBoolean(); // true
public static Int32 ToInt(this Object? value, Int32 defaultValue = 0)
```
-������ת��Ϊ32λ������
+将对象转换为32位整数。
-**֧�ֵ���������**��
-- �ַ�������ȫ�����֣�
-- �ֽ����飨С����1-4�ֽڣ�
-- DateTime��תΪUnix�룬����ʱ��ת����
-- DateTimeOffset��תΪUnix�룩
-- ʵ�� `IConvertible` ������
+**支持的输入类型**:
+- 字符串(含全角数字)
+- 字节数组(小端序,1-4字节)
+- DateTime(转为Unix秒,不含时区转换)
+- DateTimeOffset(转为Unix秒)
+- 实现 `IConvertible` 的类型
-**ʾ��**��
+**示例**:
```csharp
-// ����ת��
+// 基本转换
"123".ToInt() // 123
-" 456 ".ToInt() // 456���Զ�ȥ���ո�
-"������".ToInt() // 123��֧��ȫ�����֣�
-"1,234,567".ToInt() // 1234567��֧��ǧ��λ��
+" 456 ".ToInt() // 456(自动去除空格)
+"123".ToInt() // 123(支持全角数字)
+"1,234,567".ToInt() // 1234567(支持千分位)
-// �ֽ�����ת����С����
+// 字节数组转换(小端序)
new Byte[] { 0x01 }.ToInt() // 1
new Byte[] { 0x01, 0x00 }.ToInt() // 1
new Byte[] { 0x01, 0x00, 0x00, 0x00 }.ToInt() // 1
-// ʱ��תUnix��
-DateTime.Now.ToInt() // ��ǰUnixʱ������룩
+// 时间转Unix秒
+DateTime.Now.ToInt() // 当前Unix时间戳(秒)
-// ת��ʧ�ܷ���Ĭ��ֵ
+// 转换失败返回默认值
"abc".ToInt() // 0
"abc".ToInt(-1) // -1
((Object?)null).ToInt() // 0
@@ -81,19 +81,19 @@ DateTime.Now.ToInt() //
public static Int64 ToLong(this Object? value, Int64 defaultValue = 0)
```
-������ת��Ϊ64λ��������
+将对象转换为64位长整数。
-**�����**��
-- DateTime תΪ Unix ���루����ʱ��ת����
-- �ֽ�����֧�� 1-8 �ֽ�
+**特殊处理**:
+- DateTime 转为 Unix 毫秒(不含时区转换)
+- 字节数组支持 1-8 字节
-**ʾ��**��
+**示例**:
```csharp
"9223372036854775807".ToLong() // Int64.MaxValue
-DateTime.Now.ToLong() // ��ǰUnixʱ��������룩
+DateTime.Now.ToLong() // 当前Unix时间戳(毫秒)
```
-### ������ת��
+### 浮点数转换
#### ToDouble
@@ -101,13 +101,13 @@ DateTime.Now.ToLong() //
public static Double ToDouble(this Object? value, Double defaultValue = 0)
```
-������ת��Ϊ˫���ȸ�������
+将对象转换为双精度浮点数。
-**ʾ��**��
+**示例**:
```csharp
"3.14".ToDouble() // 3.14
-"3.14E+10".ToDouble() // 31400000000��֧�ֿ�ѧ��������
-"1,234.56".ToDouble() // 1234.56��֧��ǧ��λ��
+"3.14E+10".ToDouble() // 31400000000(支持科学计数法)
+"1,234.56".ToDouble() // 1234.56(支持千分位)
```
#### ToDecimal
@@ -116,14 +116,14 @@ public static Double ToDouble(this Object? value, Double defaultValue = 0)
public static Decimal ToDecimal(this Object? value, Decimal defaultValue = 0)
```
-������ת��Ϊ�߾��ȸ������������ڽ��ڼ���Ⱦ���Ҫ��ߵij�����
+将对象转换为高精度浮点数,适用于金融计算等精度要求高的场景。
-**ʾ��**��
+**示例**:
```csharp
-"123456789.123456789".ToDecimal() // ��ȷ����С��
+"123456789.123456789".ToDecimal() // 精确保留小数
```
-### ����ֵת��
+### 布尔值转换
#### ToBoolean
@@ -131,12 +131,12 @@ public static Decimal ToDecimal(this Object? value, Decimal defaultValue = 0)
public static Boolean ToBoolean(this Object? value, Boolean defaultValue = false)
```
-������ת��Ϊ����ֵ��
+将对象转换为布尔值。
-**֧�ֵ���ֵ**��`true`��`True`��`1`��`y`��`yes`��`on`��`enable`��`enabled`
-**֧�ֵļ�ֵ**��`false`��`False`��`0`��`n`��`no`��`off`��`disable`��`disabled`
+**支持的真值**:`true`、`True`、`1`、`y`、`yes`、`on`、`enable`、`enabled`
+**支持的假值**:`false`、`False`、`0`、`n`、`no`、`off`、`disable`、`disabled`
-**ʾ��**��
+**示例**:
```csharp
"true".ToBoolean() // true
"True".ToBoolean() // true
@@ -150,11 +150,11 @@ public static Boolean ToBoolean(this Object? value, Boolean defaultValue = false
"no".ToBoolean() // false
"off".ToBoolean() // false
-"invalid".ToBoolean() // false��Ĭ��ֵ��
-"invalid".ToBoolean(true) // true��ָ��Ĭ��ֵ��
+"invalid".ToBoolean() // false(默认值)
+"invalid".ToBoolean(true) // true(指定默认值)
```
-### ʱ��ת��
+### 时间转换
#### ToDateTime
@@ -163,35 +163,35 @@ public static DateTime ToDateTime(this Object? value)
public static DateTime ToDateTime(this Object? value, DateTime defaultValue)
```
-������ת��Ϊʱ�����ڡ�
+将对象转换为时间日期。
-**֧�ֵĸ�ʽ**��
-- ������ʱ���ַ���
-- `yyyy-M-d` ��ʽ
-- `yyyy/M/d` ��ʽ
-- `yyyyMMddHHmmss` ��ʽ
-- `yyyyMMdd` ��ʽ
-- Unix �루Int32��
-- Unix ���루Int64���Զ��жϣ�
-- UTC ��ǣ�ĩβ `Z` �� ` UTC`��
+**支持的格式**:
+- 标准日期时间字符串
+- `yyyy-M-d` 格式
+- `yyyy/M/d` 格式
+- `yyyyMMddHHmmss` 格式
+- `yyyyMMdd` 格式
+- Unix 秒(Int32)
+- Unix 毫秒(Int64,自动判断)
+- UTC 标记(末尾 `Z` 或 ` UTC`)
-**ʾ��**��
+**示例**:
```csharp
-// �ַ���ת��
+// 字符串转换
"2024-01-15".ToDateTime()
-"2024-1-5".ToDateTime() // ֧�ֵ�λ������
+"2024-1-5".ToDateTime() // 支持单位数月日
"2024/01/15".ToDateTime()
"20240115".ToDateTime()
"20240115120000".ToDateTime()
"2024-01-15 12:30:45".ToDateTime()
-"2024-01-15T12:30:45Z".ToDateTime() // UTC ʱ��
+"2024-01-15T12:30:45Z".ToDateTime() // UTC 时间
-// Unix ʱ���ת��
-1705276800.ToDateTime() // Unix ��
-1705276800000L.ToDateTime() // Unix ���루�Զ��жϣ�
+// Unix 时间戳转换
+1705276800.ToDateTime() // Unix 秒
+1705276800000L.ToDateTime() // Unix 毫秒(自动判断)
```
-> **ע��**������תʱ��ʱ������ UTC �뱾��ʱ��ת�����������������У��豸����λ�ڲ�ͬʱ��������ͳһʹ�� UTC ʱ�䴫�����ת����
+> **注意**:整数转时间时不进行 UTC 与本地时间转换。在物联网场景中,设备可能位于不同时区,建议统一使用 UTC 时间传输后再转换。
#### ToDateTimeOffset
@@ -200,9 +200,9 @@ public static DateTimeOffset ToDateTimeOffset(this Object? value)
public static DateTimeOffset ToDateTimeOffset(this Object? value, DateTimeOffset defaultValue)
```
-������ת��Ϊ��ʱ����ʱ�����ڡ�
+将对象转换为带时区的时间日期。
-### ʱ���ʽ��
+### 时间格式化
#### ToFullString
@@ -211,13 +211,13 @@ public static String ToFullString(this DateTime value, String? emptyValue = null
public static String ToFullString(this DateTime value, Boolean useMillisecond, String? emptyValue = null)
```
-��ʱ���ʽ��Ϊ `yyyy-MM-dd HH:mm:ss` ����ʽ��
+将时间格式化为 `yyyy-MM-dd HH:mm:ss` 标准格式。
-**����˵��**��
-- `useMillisecond`���Ƿ�������룬��ʽΪ `yyyy-MM-dd HH:mm:ss.fff`
-- `emptyValue`����ʱ��Ϊ `MinValue` ʱ��ʾ������ַ���
+**参数说明**:
+- `useMillisecond`:是否包含毫秒,格式为 `yyyy-MM-dd HH:mm:ss.fff`
+- `emptyValue`:当时间为 `MinValue` 时显示的替代字符串
-**ʾ��**��
+**示例**:
```csharp
DateTime.Now.ToFullString() // "2024-01-15 12:30:45"
DateTime.Now.ToFullString(true) // "2024-01-15 12:30:45.123"
@@ -231,26 +231,26 @@ DateTime.MinValue.ToFullString("N/A") // "N/A"
public static DateTime Trim(this DateTime value, String format = "s")
```
-�ض�ʱ�侫�ȡ�
+截断时间精度。
-**��ʽ����**��
-- `ns`�����뾫�ȣ�ʵ��Ϊ 100ns���� 1 tick��
-- `us`���뾫��
-- `ms`�����뾫��
-- `s`���뾫�ȣ�Ĭ�ϣ�
-- `m`�����Ӿ���
-- `h`��Сʱ����
+**格式参数**:
+- `ns`:纳秒精度(实际为 100ns,即 1 tick)
+- `us`:微秒精度
+- `ms`:毫秒精度
+- `s`:秒精度(默认)
+- `m`:分钟精度
+- `h`:小时精度
-**ʾ��**��
+**示例**:
```csharp
var dt = new DateTime(2024, 1, 15, 12, 30, 45, 123);
dt.Trim("s") // 2024-01-15 12:30:45.000
dt.Trim("m") // 2024-01-15 12:30:00.000
dt.Trim("h") // 2024-01-15 12:00:00.000
-dt.Trim("ms") // ��������
+dt.Trim("ms") // 保留毫秒
```
-### �ֽڵ�λ��ʽ��
+### 字节单位格式化
#### ToGMK
@@ -259,21 +259,21 @@ public static String ToGMK(this Int64 value, String? format = null)
public static String ToGMK(this UInt64 value, String? format = null)
```
-���ֽ�����ʽ��Ϊ�ɶ��ĵ�λ�ַ�����
+将字节数格式化为可读的单位字符串。
-**ʾ��**��
+**示例**:
```csharp
1024L.ToGMK() // "1.00K"
1048576L.ToGMK() // "1.00M"
1073741824L.ToGMK() // "1.00G"
1099511627776L.ToGMK() // "1.00T"
-// �Զ����ʽ
+// 自定义格式
1536L.ToGMK("n1") // "1.5K"
1536L.ToGMK("n0") // "2K"
```
-### �쳣����
+### 异常处理
#### GetTrue
@@ -281,13 +281,13 @@ public static String ToGMK(this UInt64 value, String? format = null)
public static Exception GetTrue(this Exception ex)
```
-��ȡ�쳣����ʵ�ڲ��쳣���Զ���� `AggregateException`��`TargetInvocationException`��`TypeInitializationException` �Ȱ�װ�쳣��
+获取异常的真实内部异常,自动解包 `AggregateException`、`TargetInvocationException`、`TypeInitializationException` 等包装异常。
-**ʾ��**��
+**示例**:
```csharp
try
{
- // �����׳���װ�쳣�Ĵ���
+ // 可能抛出包装异常的代码
}
catch (Exception ex)
{
@@ -302,18 +302,18 @@ catch (Exception ex)
public static String GetMessage(this Exception ex)
```
-��ȡ��ʽ�����쳣��Ϣ�����˵�����Ҫ�Ķ�ջ��Ϣ���� `System.Runtime.ExceptionServices` �ȣ���
+获取格式化的异常消息,过滤掉不必要的堆栈信息(如 `System.Runtime.ExceptionServices` 等)。
-## �Զ���ת��
+## 自定义转换
-ͨ���滻 `Utility.Convert` �����Զ�����������ת������Ϊ��
+通过替换 `Utility.Convert` 可以自定义所有类型转换的行为:
```csharp
public class MyConvert : DefaultConvert
{
public override Int32 ToInt(Object? value, Int32 defaultValue)
{
- // �Զ���ת����
+ // 自定义转换逻辑
if (value is MyCustomType mct)
return mct.Value;
@@ -321,54 +321,54 @@ public class MyConvert : DefaultConvert
}
}
-// ȫ���滻
+// 全局替换
Utility.Convert = new MyConvert();
```
-## ���ʵ��
+## 最佳实践
-### 1. ʼ���ṩ�������Ĭ��ֵ
+### 1. 始终提供有意义的默认值
```csharp
-// �Ƽ�����ȷָ��Ĭ��ֵ
+// 推荐:明确指定默认值
var port = config["Port"].ToInt(8080);
var timeout = config["Timeout"].ToInt(30);
-// ���Ƽ���ʹ����ʽĬ��ֵ 0 ���ܵ�������
-var port = config["Port"].ToInt(); // �������ȱʧ���˿�Ϊ 0
+// 不推荐:使用隐式默认值 0 可能导致问题
+var port = config["Port"].ToInt(); // 如果配置缺失,端口为 0
```
-### 2. ʱ���ת��ע��ʱ��
+### 2. 时间戳转换注意时区
```csharp
-// �������������豸�ϱ� UTC ʱ���
-var deviceTime = timestamp.ToDateTime(); // ����ʱ��ת��
-var localTime = deviceTime.ToLocalTime(); // תΪ����ʱ��
+// 物联网场景:设备上报 UTC 时间戳
+var deviceTime = timestamp.ToDateTime(); // 不含时区转换
+var localTime = deviceTime.ToLocalTime(); // 转为本地时间
-// ����ʹ�� DateTimeOffset
+// 或者使用 DateTimeOffset
var dto = timestamp.ToDateTimeOffset();
```
-### 3. ������ʽ���ü���
+### 3. 利用链式调用简化代码
```csharp
-// ��ͳд��
+// 传统写法
Int32 value;
if (!Int32.TryParse(str, out value))
value = defaultValue;
-// NewLife �
+// NewLife 写法
var value = str.ToInt(defaultValue);
```
-## ����˵��
+## 性能说明
-- ����ת��������Գ������ͣ�String��Int32 �ȣ������˿���·���Ż�
-- �ַ���ת��ʹ�� `Span<T>` ���ⲻ��Ҫ���ڴ����
-- ʱ���ʽ������ʹ�� `ToString()` ��ʽ���������ֶ�ƴ����������
-- �ֽ�����ת��ֱ��ʹ�� `BitConverter`�������
+- 所有转换方法针对常见类型(String、Int32 等)进行了快速路径优化
+- 字符串转换使用 `Span<T>` 避免不必要的内存分配
+- 时间格式化避免使用 `ToString()` 格式化,采用手动拼接提升性能
+- 字节数组转换直接使用 `BitConverter`,无额外开销
-## �������
+## 相关链接
-- [�ַ�����չ StringHelper](string_helper-�ַ�����չStringHelper.md)
-- [������չ IOHelper](io_helper-������չIOHelper.md)
+- [字符串扩展 StringHelper](string_helper-字符串扩展StringHelper.md)
+- [数据扩展 IOHelper](io_helper-数据扩展IOHelper.md)
diff --git "a/Doc/\347\274\223\345\255\230\347\263\273\347\273\237ICache.md" "b/Doc/\347\274\223\345\255\230\347\263\273\347\273\237ICache.md"
index 3308d28..a043d77 100644
--- "a/Doc/\347\274\223\345\255\230\347\263\273\347\273\237ICache.md"
+++ "b/Doc/\347\274\223\345\255\230\347\263\273\347\273\237ICache.md"
@@ -1,175 +1,175 @@
-# ����ϵͳ ICache
+# 缓存系统 ICache
-## ����
+## 概述
-NewLife.Core �ṩ��ͳһ�Ļ���ӿ� `ICache`��֧���ڴ滺�桢Redis ����ȶ���ʵ�֡�ͨ��ͳһ�ӿڣ������ڲ�ͬ���������л�����ʵ�֣�ͬʱ֧�ֹ���ʱ�䡢ԭ�Ӳ��������������ȸ����ԡ�
+NewLife.Core 提供了统一的缓存接口 `ICache`,支持内存缓存、Redis 缓存等多种实现。通过统一接口,可以在不同环境下无缝切换缓存实现,同时支持过期时间、原子操作、批量操作等高级特性。
-**�����ռ�**��`NewLife.Caching`
-**�ĵ���ַ**��https://newlifex.com/core/icache
+**命名空间**:`NewLife.Caching`
+**文档地址**:https://newlifex.com/core/icache
-## ��������
+## 核心特性
-- **ͳһ�ӿ�**��`ICache` �ӿڶ�����������
-- **������**��`MemoryCache` ���� `ConcurrentDictionary`����ֵ���ܴ� 10 �� ops
-- **�Զ�����**��֧����Թ���ʱ�䣨TTL��
-- **ԭ�Ӳ���**���������ݼ����滻��ԭ�Ӳ���
-- **��������**��������д�������翪��
-- **LRU ��̭**���ڴ滺�泬����ʱ�Զ�����
+- **统一接口**:`ICache` 接口定义标准缓存操作
+- **高性能**:`MemoryCache` 基于 `ConcurrentDictionary`,峰值性能达 10 亿 ops
+- **自动过期**:支持相对过期时间(TTL)
+- **原子操作**:递增、递减、替换等原子操作
+- **批量操作**:批量读写减少网络开销
+- **LRU 淘汰**:内存缓存超容量时自动清理
-## ���ٿ�ʼ
+## 快速开始
-### ����ʹ��
+### 基本使用
```csharp
using NewLife.Caching;
-// ʹ��Ĭ���ڴ滺��
+// 使用默认内存缓存
var cache = MemoryCache.Instance;
-// ���û��棨60����ڣ�
-cache.Set("name", "����", 60);
+// 设置缓存(60秒过期)
+cache.Set("name", "张三", 60);
-// ��ȡ����
+// 获取缓存
var name = cache.Get<String>("name");
-// ɾ������
+// 删除缓存
cache.Remove("name");
```
-### ����
+### 常用操作
```csharp
var cache = MemoryCache.Instance;
-// ����Ƿ����
+// 检查是否存在
if (cache.ContainsKey("user:1"))
{
var user = cache.Get<User>("user:1");
}
-// ��ȡ�����ӣ����洩������
+// 获取或添加(缓存穿透保护)
var data = cache.GetOrAdd("data:key", k =>
{
- // ���治����ʱ��ִ�д˻ص���ȡ����
+ // 缓存不存在时,执行此回调获取数据
return LoadFromDatabase(k);
}, 300);
-// ԭ�ӵ���
+// 原子递增
var count = cache.Increment("visit:count", 1);
```
-## API �ο�
+## API 参考
-### ICache �ӿ�
+### ICache 接口
-#### ��������
+#### 基本属性
```csharp
-/// <summary>��������</summary>
+/// <summary>缓存名称</summary>
String Name { get; }
-/// <summary>Ĭ�Ϲ���ʱ�䣨�룩</summary>
+/// <summary>默认过期时间(秒)</summary>
Int32 Expire { get; set; }
-/// <summary>����������</summary>
+/// <summary>缓存项总数</summary>
Int32 Count { get; }
-/// <summary>������</summary>
+/// <summary>所有缓存键</summary>
ICollection<String> Keys { get; }
```
-#### ��������
+#### 基础操作
```csharp
-/// <summary>����Ƿ����</summary>
+/// <summary>检查是否存在</summary>
Boolean ContainsKey(String key);
-/// <summary>���û���</summary>
-/// <param name="expire">����������-1ʹ��Ĭ�ϣ�0��������</param>
+/// <summary>设置缓存</summary>
+/// <param name="expire">过期秒数。-1使用默认,0永不过期</param>
Boolean Set<T>(String key, T value, Int32 expire = -1);
-/// <summary>���û��棨TimeSpan��</summary>
+/// <summary>设置缓存(TimeSpan)</summary>
Boolean Set<T>(String key, T value, TimeSpan expire);
-/// <summary>��ȡ����</summary>
+/// <summary>获取缓存</summary>
T Get<T>(String key);
-/// <summary>���Ի�ȡ��������洩��</summary>
+/// <summary>尝试获取(解决缓存穿透)</summary>
Boolean TryGetValue<T>(String key, out T value);
-/// <summary>ɾ������</summary>
+/// <summary>删除缓存</summary>
Int32 Remove(String key);
-/// <summary>����ɾ��</summary>
+/// <summary>批量删除</summary>
Int32 Remove(params String[] keys);
-/// <summary>��������</summary>
+/// <summary>清空所有缓存</summary>
void Clear();
```
-#### ����ʱ�����
+#### 过期时间管理
```csharp
-/// <summary>���ù���ʱ��</summary>
+/// <summary>设置过期时间</summary>
Boolean SetExpire(String key, TimeSpan expire);
-/// <summary>��ȡʣ�����ʱ��</summary>
+/// <summary>获取剩余过期时间</summary>
TimeSpan GetExpire(String key);
```
-#### ��������
+#### 批量操作
```csharp
-/// <summary>������ȡ</summary>
+/// <summary>批量获取</summary>
IDictionary<String, T?> GetAll<T>(IEnumerable<String> keys);
-/// <summary>��������</summary>
+/// <summary>批量设置</summary>
void SetAll<T>(IDictionary<String, T> values, Int32 expire = -1);
```
-#### ������
+#### 高级操作
```csharp
-/// <summary>���ӣ��Ѵ���ʱ�����£�</summary>
+/// <summary>添加(已存在时不更新)</summary>
Boolean Add<T>(String key, T value, Int32 expire = -1);
-/// <summary>�滻�����ؾ�ֵ</summary>
+/// <summary>替换并返回旧值</summary>
T Replace<T>(String key, T value);
-/// <summary>��ȡ������</summary>
+/// <summary>获取或添加</summary>
T GetOrAdd<T>(String key, Func<String, T> callback, Int32 expire = -1);
-/// <summary>ԭ�ӵ���</summary>
+/// <summary>原子递增</summary>
Int64 Increment(String key, Int64 value);
Double Increment(String key, Double value);
-/// <summary>ԭ�ӵݼ�</summary>
+/// <summary>原子递减</summary>
Int64 Decrement(String key, Int64 value);
Double Decrement(String key, Double value);
```
-### MemoryCache ��
+### MemoryCache 类
```csharp
public class MemoryCache : Cache
{
- /// <summary>Ĭ��ʵ��</summary>
+ /// <summary>默认实例</summary>
public static MemoryCache Instance { get; set; }
- /// <summary>����������ʱLRU��̭��Ĭ��100000</summary>
+ /// <summary>容量。超标时LRU淘汰,默认100000</summary>
public Int32 Capacity { get; set; }
- /// <summary>��ʱ����������룩��Ĭ��60</summary>
+ /// <summary>定时清理间隔(秒),默认60</summary>
public Int32 Period { get; set; }
- /// <summary>����������¼�</summary>
+ /// <summary>缓存键过期事件</summary>
public event EventHandler<KeyEventArgs>? KeyExpired;
}
```
-## ʹ�ó���
+## 使用场景
-### 1. ���ݻ���
+### 1. 数据缓存
```csharp
public class UserService
@@ -185,63 +185,63 @@ public class UserService
{
var key = $"user:{id}";
- // �Ȳ黺��
+ // 先查缓存
if (_cache.TryGetValue<User>(key, out var user))
return user;
- // ����δ���У������ݿ�
+ // 缓存未命中,查数据库
user = LoadUserFromDb(id);
if (user != null)
- _cache.Set(key, user, 300); // ����5����
+ _cache.Set(key, user, 300); // 缓存5分钟
return user;
}
}
```
-### 2. ��ֹ���洩
+### 2. 防止缓存穿透
```csharp
-// ʹ�� GetOrAdd ��ֹ���洩
+// 使用 GetOrAdd 防止缓存穿透
var user = cache.GetOrAdd($"user:{id}", key =>
{
- // ��ʹ���ݿⷵ�� null��Ҳ�ᱻ����
+ // 即使数据库返回 null,也会被缓存
return LoadUserFromDb(id);
}, 60);
-// ʹ�� TryGetValue ���ֿ�ֵ�Ͳ�����
+// 使用 TryGetValue 区分空值和不存在
if (cache.TryGetValue<User?>($"user:{id}", out var user))
{
- // �����ڣ�����Ϊ null��
+ // 键存在(可能为 null)
return user;
}
else
{
- // �������ڣ���Ҫ��ѯ���ݿ�
+ // 键不存在,需要查询数据库
}
```
-### 3. ������
+### 3. 计数器
```csharp
-// ���ʼ���
+// 访问计数
var count = cache.Increment("page:home:views", 1);
-// ��������
+// 限流计数
var requests = cache.Increment($"rate:{userId}", 1);
if (requests == 1)
{
- // �״η��ʣ����ù���ʱ��
+ // 首次访问,设置过期时间
cache.SetExpire($"rate:{userId}", TimeSpan.FromMinutes(1));
}
if (requests > 100)
{
- throw new Exception("�������Ƶ��");
+ throw new Exception("请求过于频繁");
}
```
-### 4. �ֲ�ʽ������ʵ��
+### 4. 分布式锁简易实现
```csharp
public class SimpleLock
@@ -250,7 +250,7 @@ public class SimpleLock
public Boolean TryLock(String key, Int32 seconds = 30)
{
- // Add ֻ�ڲ�����ʱ�ɹ�
+ // Add 只在不存在时成功
return _cache.Add($"lock:{key}", DateTime.Now, seconds);
}
@@ -260,13 +260,13 @@ public class SimpleLock
}
}
-// ʹ��
+// 使用
var locker = new SimpleLock(cache);
if (locker.TryLock("order:create"))
{
try
{
- // ִ��ҵ��
+ // 执行业务
}
finally
{
@@ -275,13 +275,13 @@ if (locker.TryLock("order:create"))
}
```
-### 5. �Ự����
+### 5. 会话缓存
```csharp
public class SessionCache
{
private readonly ICache _cache;
- private readonly Int32 _expire = 1800; // 30����
+ private readonly Int32 _expire = 1800; // 30分钟
public void Set(String sessionId, Object data)
{
@@ -295,7 +295,7 @@ public class SessionCache
if (data != null)
{
- // ����
+ // 续期
_cache.SetExpire(key, TimeSpan.FromSeconds(_expire));
}
@@ -304,10 +304,10 @@ public class SessionCache
}
```
-### 6. ����������
+### 6. 批量操作优化
```csharp
-// ������ȡ
+// 批量获取
var keys = new[] { "user:1", "user:2", "user:3" };
var users = cache.GetAll<User>(keys);
@@ -316,44 +316,44 @@ foreach (var kv in users)
Console.WriteLine($"{kv.Key}: {kv.Value?.Name}");
}
-// ��������
+// 批量设置
var items = new Dictionary<String, User>
{
- ["user:1"] = new User { Id = 1, Name = "����" },
- ["user:2"] = new User { Id = 2, Name = "����" }
+ ["user:1"] = new User { Id = 1, Name = "张三" },
+ ["user:2"] = new User { Id = 2, Name = "李四" }
};
cache.SetAll(items, 300);
```
-## ����ʱ��˵��
+## 过期时间说明
-| expire ֵ | ���� |
+| expire 值 | 含义 |
|-----------|------|
-| < 0 | ʹ��Ĭ�Ϲ���ʱ�� `Expire` |
-| = 0 | �������� |
-| > 0 | �������� N ������ |
+| < 0 | 使用默认过期时间 `Expire` |
+| = 0 | 永不过期 |
+| > 0 | 从现在起 N 秒后过期 |
```csharp
-// ʹ��Ĭ�Ϲ���ʱ��
+// 使用默认过期时间
cache.Set("key1", value);
-// ��������
+// 永不过期
cache.Set("key2", value, 0);
-// 1Сʱ�����
+// 1小时后过期
cache.Set("key3", value, 3600);
-// ʹ�� TimeSpan
+// 使用 TimeSpan
cache.Set("key4", value, TimeSpan.FromHours(1));
```
-## ����ע��
+## 依赖注入
```csharp
-// ע�Ỻ�����
+// 注册缓存服务
services.AddSingleton<ICache>(MemoryCache.Instance);
-// ����ʵ��
+// 或创建新实例
services.AddSingleton<ICache>(sp => new MemoryCache
{
Capacity = 50000,
@@ -361,67 +361,67 @@ services.AddSingleton<ICache>(sp => new MemoryCache
});
```
-## ������淶
+## 缓存键规范
-����ʹ��ð�ŷָ��IJ㼶������
+建议使用冒号分隔的层级键名:
```
-����:��ʶ[:������]
+类型:标识[:子类型]
user:123
user:123:profile
order:2024:001
config:app:debug
```
-## ���ʵ��
+## 最佳实践
-### 1. ������������
+### 1. 合理设置容量
```csharp
var cache = new MemoryCache
{
- Capacity = 100000, // �����ڴ����
- Period = 60 // �������
+ Capacity = 100000, // 根据内存调整
+ Period = 60 // 清理间隔
};
```
-### 2. ���������¼�
+### 2. 监听过期事件
```csharp
var cache = new MemoryCache();
cache.KeyExpired += (s, e) =>
{
- XTrace.WriteLine($"�������: {e.Key}");
- // ���������ﴥ������Ԥ��
+ XTrace.WriteLine($"缓存过期: {e.Key}");
+ // 可以在这里触发数据预热
};
```
-### 3. ����� Key
+### 3. 避免大 Key
```csharp
-// ���Ƽ����洢�����
+// 不推荐:存储大对象
cache.Set("bigdata", hugeList);
-// �Ƽ�����ִ洢
+// 推荐:拆分存储
foreach (var item in hugeList)
{
cache.Set($"item:{item.Id}", item);
}
```
-### 4. ʹ��ǰ����
+### 4. 使用前缀隔离
```csharp
-// ��ͬģ��ʹ�ò�ͬǰ
+// 不同模块使用不同前缀
cache.Set("user:session:abc", data);
cache.Set("order:temp:123", data);
-// ��ǰ����ɾ��
+// 按前缀批量删除
cache.Remove("user:session:*");
```
-## �������
+## 相关链接
-- [����� Pool](pool-�����Pool.md)
-- [�ֵ仺�� DictionaryCache](dictionary_cache-�ֵ仺��.md)
-- [ѩ���㷨 Snowflake](snowflake-ѩ���㷨Snowflake.md)
+- [对象池 Pool](pool-对象池Pool.md)
+- [字典缓存 DictionaryCache](dictionary_cache-字典缓存.md)
+- [雪花算法 Snowflake](snowflake-雪花算法Snowflake.md)
diff --git "a/Doc/\350\267\257\345\276\204\346\211\251\345\261\225PathHelper.md" "b/Doc/\350\267\257\345\276\204\346\211\251\345\261\225PathHelper.md"
index e4aeac4..d79f81a 100644
--- "a/Doc/\350\267\257\345\276\204\346\211\251\345\261\225PathHelper.md"
+++ "b/Doc/\350\267\257\345\276\204\346\211\251\345\261\225PathHelper.md"
@@ -1,44 +1,44 @@
-# ·����չ PathHelper
+# 路径扩展 PathHelper
-## ����
+## 概述
-`PathHelper` �� NewLife.Core �е�·�����������࣬�ṩ��ƽ̨���ļ�·��������Ŀ¼�������ļ�ѹ����ѹ����ϣУ��ȹ��ܡ����ܴ������·���;���·�����Զ����� Windows �� Linux ��·���ָ�����
+`PathHelper` 是 NewLife.Core 中的路径操作工具类,提供跨平台的文件路径处理、目录管理、文件压缩解压、哈希校验等功能。智能处理相对路径和绝对路径,自动适配 Windows 和 Linux 的路径分隔符。
-**�����ռ�**��`System.IO`������ֱ��ʹ�ã�����������ã�
-**�ĵ���ַ**��https://newlifex.com/core/path_helper
+**命名空间**:`System.IO`(便于直接使用,无需额外引用)
+**文档地址**:https://newlifex.com/core/path_helper
-## ��������
+## 核心特性
-- **��ƽ̨·������**���Զ����� Windows��`\`���� Linux��`/`��·���ָ���
-- **����·������**��֧�����·��������·��������·��
-- **��������֧��**��ͨ�������в������������û���Ŀ¼
-- **ѹ����ѹ֧��**��֧�� zip��tar��tar.gz��7z �ȸ�ʽ
-- **�ļ���ϣУ��**��֧�� MD5��SHA1��SHA256��SHA512��CRC32
+- **跨平台路径处理**:自动适配 Windows(`\`)和 Linux(`/`)路径分隔符
+- **智能路径解析**:支持相对路径、绝对路径、网络路径
+- **函数计算支持**:通过命令行参数或环境变量配置基础目录
+- **压缩解压支持**:支持 zip、tar、tar.gz、7z 等格式
+- **文件哈希校验**:支持 MD5、SHA1、SHA256、SHA512、CRC32
-## ���ٿ�ʼ
+## 快速开始
```csharp
using System.IO;
-// ��ȡ����·��
+// 获取完整路径
var path = "config/app.json".GetFullPath();
-// ȷ��Ŀ¼����
+// 确保目录存在
"logs/2024/01/".EnsureDirectory(false);
-// �ϲ�·��
+// 合并路径
var file = "data".CombinePath("users", "config.json");
-// ѹ��Ŀ¼
+// 压缩目录
"output".AsDirectory().Compress("backup.zip");
-// ��֤�ļ���ϣ
+// 验证文件哈希
var valid = "app.exe".AsFile().VerifyHash("md5$1234567890abcdef");
```
-## API �ο�
+## API 参考
-### ·������
+### 路径属性
#### BasePath
@@ -46,12 +46,12 @@ var valid = "app.exe".AsFile().VerifyHash("md5$1234567890abcdef");
public static String? BasePath { get; set; }
```
-����Ŀ¼������ `GetBasePath` ��������Ҫ���� X ����ڲ���Ŀ¼��ר��Ϊ������������ơ�
+基础目录,用于 `GetBasePath` 方法。主要用于 X 组件内部各目录,专门为函数计算而定制。
-**���÷�ʽ**�������ȼ�����
-1. ���������`-BasePath /app/data` �� `--BasePath /app/data`
-2. ����������`BasePath=/app/data`
-3. Ĭ��ֵ��Ӧ�ó��������Ŀ¼
+**配置方式**(按优先级):
+1. 命令行参数:`-BasePath /app/data` 或 `--BasePath /app/data`
+2. 环境变量:`BasePath=/app/data`
+3. 默认值:应用程序域基础目录
#### BaseDirectory
@@ -59,9 +59,9 @@ public static String? BasePath { get; set; }
public static String? BaseDirectory { get; set; }
```
-��Ŀ¼������ `GetFullPath` ������֧��ͨ�������в����ͻ����������á�
+基准目录,用于 `GetFullPath` 方法。支持通过命令行参数和环境变量配置。
-### ·��ת��
+### 路径转换
#### GetFullPath
@@ -69,30 +69,30 @@ public static String? BaseDirectory { get; set; }
public static String GetFullPath(this String path)
```
-��ȡ�ļ���Ŀ¼����Ӧ�ó������Ŀ¼��ȫ·����
+获取文件或目录基于应用程序域基目录的全路径。
-**�ص�**��
-- �Զ��������·��
-- �Զ�ת��·���ָ���
-- ֧������·����`\\server\share`��
-- ֧�� `~` ��ͷ��·��
+**特点**:
+- 自动处理相对路径
+- 自动转换路径分隔符
+- 支持网络路径(`\\server\share`)
+- 支持 `~` 开头的路径
-**ʾ��**��
+**示例**:
```csharp
-// ���·��ת����·��
+// 相对路径转绝对路径
"config/app.json".GetFullPath()
// Windows: C:\MyApp\config\app.json
// Linux: /home/user/myapp/config/app.json
-// ���Ǿ���·����ԭ������
+// 已是绝对路径则原样返回
"C:\\temp\\file.txt".GetFullPath() // C:\temp\file.txt
"/var/log/app.log".GetFullPath() // /var/log/app.log
-// ����·��
+// 网络路径
"\\\\server\\share\\file.txt".GetFullPath() // \\server\share\file.txt
-// ~ ��ͷ��·��
-"~/config/app.json".GetFullPath() // ȥ�� ~ ��ƴ�ӻ���Ŀ¼
+// ~ 开头的路径
+"~/config/app.json".GetFullPath() // 去除 ~ 后拼接基础目录
```
#### GetBasePath
@@ -101,12 +101,12 @@ public static String GetFullPath(this String path)
public static String GetBasePath(this String path)
```
-��ȡ�ļ���Ŀ¼��ȫ·�������� X ����ڲ���Ŀ¼��
+获取文件或目录的全路径,用于 X 组件内部各目录。
-**ʾ��**��
+**示例**:
```csharp
"logs/app.log".GetBasePath()
-// ���� BasePath ������·��
+// 基于 BasePath 的完整路径
```
#### GetCurrentPath
@@ -115,15 +115,15 @@ public static String GetBasePath(this String path)
public static String GetCurrentPath(this String path)
```
-��ȡ�ļ���Ŀ¼���ڵ�ǰ����Ŀ¼��ȫ·����
+获取文件或目录基于当前工作目录的全路径。
-**ʾ��**��
+**示例**:
```csharp
"output/result.txt".GetCurrentPath()
-// ���� Environment.CurrentDirectory ������·��
+// 基于 Environment.CurrentDirectory 的完整路径
```
-### Ŀ¼����
+### 目录操作
#### EnsureDirectory
@@ -131,23 +131,23 @@ public static String GetCurrentPath(this String path)
public static String EnsureDirectory(this String path, Boolean isfile = true)
```
-ȷ��Ŀ¼���ڣ�������������
+确保目录存在,若不存在则创建。
-**����˵��**��
-- `isfile`��·���Ƿ�Ϊ�ļ�·����`true` ʱȡĿ¼���֣�б�ܽ�β��·��ʼ����ΪĿ¼��
+**参数说明**:
+- `isfile`:路径是否为文件路径。`true` 时取目录部分;斜杠结尾的路径始终视为目录。
-**ʾ��**��
+**示例**:
```csharp
-// ȷ���ļ�����Ŀ¼����
+// 确保文件所在目录存在
"logs/2024/01/app.log".EnsureDirectory(true);
-// ���� logs/2024/01/ Ŀ¼
+// 创建 logs/2024/01/ 目录
-// ȷ��Ŀ¼��������
+// 确保目录本身存在
"data/cache/".EnsureDirectory(false);
-// ���� data/cache/ Ŀ¼
+// 创建 data/cache/ 目录
-// б�ܽ�β��·��ʼ����ΪĿ¼
-"output/temp/".EnsureDirectory(); // isfile ����������
+// 斜杠结尾的路径始终视为目录
+"output/temp/".EnsureDirectory(); // isfile 参数被忽略
```
#### CombinePath
@@ -156,19 +156,19 @@ public static String EnsureDirectory(this String path, Boolean isfile = true)
public static String CombinePath(this String? path, params String[] ps)
```
-�ϲ����·����
+合并多段路径。
-**ʾ��**��
+**示例**:
```csharp
"data".CombinePath("users", "config.json")
// Windows: data\users\config.json
// Linux: data/users/config.json
-// ֧�ֿ�·��
+// 支持空路径
"".CombinePath("logs", "app.log") // logs/app.log
```
-### �����
+### 文件操作
#### AsFile
@@ -176,14 +176,14 @@ public static String CombinePath(this String? path, params String[] ps)
public static FileInfo AsFile(this String file)
```
-��·���ַ���ת��Ϊ `FileInfo` ����
+将路径字符串转换为 `FileInfo` 对象。
-**ʾ��**��
+**示例**:
```csharp
var fi = "config/app.json".AsFile();
if (fi.Exists)
{
- Console.WriteLine($"�ļ���С: {fi.Length}");
+ Console.WriteLine($"文件大小: {fi.Length}");
}
```
@@ -193,16 +193,16 @@ if (fi.Exists)
public static Byte[] ReadBytes(this FileInfo file, Int32 offset = 0, Int32 count = -1)
```
-���ļ���ȡ�ֽ����ݡ�
+从文件读取字节数据。
-**ʾ��**��
+**示例**:
```csharp
-// ��ȡ�����ļ�
+// 读取整个文件
var data = "data.bin".AsFile().ReadBytes();
-// ��ȡָ����Χ
-var header = "data.bin".AsFile().ReadBytes(0, 100); // ǰ100�ֽ�
-var tail = "data.bin".AsFile().ReadBytes(1000, 50); // ��1000��ʼ��50�ֽ�
+// 读取指定范围
+var header = "data.bin".AsFile().ReadBytes(0, 100); // 前100字节
+var tail = "data.bin".AsFile().ReadBytes(1000, 50); // 从1000开始的50字节
```
#### WriteBytes
@@ -211,9 +211,9 @@ var tail = "data.bin".AsFile().ReadBytes(1000, 50); //
public static FileInfo WriteBytes(this FileInfo file, Byte[] data, Int32 offset = 0)
```
-���ļ�д���ֽ����ݡ�
+向文件写入字节数据。
-**ʾ��**��
+**示例**:
```csharp
var data = new Byte[] { 1, 2, 3, 4, 5 };
"output.bin".AsFile().WriteBytes(data);
@@ -225,18 +225,18 @@ var data = new Byte[] { 1, 2, 3, 4, 5 };
public static Boolean CopyToIfNewer(this FileInfo fi, String destFileName)
```
-����Դ�ļ���Ŀ���ļ���ʱ�Ÿ��ơ�
+仅当源文件比目标文件新时才复制。
-**ʾ��**��
+**示例**:
```csharp
var source = "src/app.dll".AsFile();
if (source.CopyToIfNewer("dest/app.dll"))
{
- Console.WriteLine("�ļ��Ѹ���");
+ Console.WriteLine("文件已更新");
}
```
-### Ŀ¼����
+### 目录操作
#### AsDirectory
@@ -244,14 +244,14 @@ if (source.CopyToIfNewer("dest/app.dll"))
public static DirectoryInfo AsDirectory(this String dir)
```
-��·���ַ���ת��Ϊ `DirectoryInfo` ����
+将路径字符串转换为 `DirectoryInfo` 对象。
-**ʾ��**��
+**示例**:
```csharp
var di = "data/cache".AsDirectory();
if (di.Exists)
{
- Console.WriteLine($"���� {di.GetFiles().Length} ���ļ�");
+ Console.WriteLine($"包含 {di.GetFiles().Length} 个文件");
}
```
@@ -261,22 +261,22 @@ if (di.Exists)
public static IEnumerable<FileInfo> GetAllFiles(this DirectoryInfo di, String? exts = null, Boolean allSub = false)
```
-��ȡĿ¼�����з����������ļ���֧�ֶ���չ��ƥ�䡣
+获取目录内所有符合条件的文件,支持多扩展名匹配。
-**ʾ��**��
+**示例**:
```csharp
var dir = "src".AsDirectory();
-// ��ȡ�����ļ�
+// 获取所有文件
var allFiles = dir.GetAllFiles();
-// ��ȡָ����չ���ļ�
+// 获取指定扩展名文件
var csharpFiles = dir.GetAllFiles("*.cs");
-// ����չ��ƥ�䣨�ֺš����ߡ����ŷָ���
+// 多扩展名匹配(分号、竖线、逗号分隔)
var codeFiles = dir.GetAllFiles("*.cs;*.xaml;*.json");
-// ������Ŀ¼
+// 包含子目录
var allCsharp = dir.GetAllFiles("*.cs", true);
```
@@ -286,15 +286,15 @@ var allCsharp = dir.GetAllFiles("*.cs", true);
public static String[] CopyTo(this DirectoryInfo di, String destDirName, String? exts = null, Boolean allSub = false, Action<String>? callback = null)
```
-����Ŀ¼�е��ļ���Ŀ��Ŀ¼��
+复制目录中的文件到目标目录。
-**ʾ��**��
+**示例**:
```csharp
var copied = "src".AsDirectory().CopyTo("backup", "*.cs;*.json", true, name =>
{
- Console.WriteLine($"����: {name}");
+ Console.WriteLine($"复制: {name}");
});
-Console.WriteLine($"������ {copied.Length} ���ļ�");
+Console.WriteLine($"共复制 {copied.Length} 个文件");
```
#### CopyToIfNewer
@@ -303,73 +303,73 @@ Console.WriteLine($"
public static String[] CopyToIfNewer(this DirectoryInfo di, String destDirName, String? exts = null, Boolean allSub = false, Action<String>? callback = null)
```
-������ԴĿ¼�б�Ŀ��Ŀ¼���µ��ļ���
+仅复制源目录中比目标目录更新的文件。
-**ʾ��**��
+**示例**:
```csharp
var updated = "src".AsDirectory().CopyToIfNewer("dest", "*.dll;*.exe", true);
```
-### ѹ����ѹ
+### 压缩解压
-#### Extract���ļ���ѹ��
+#### Extract(文件解压)
```csharp
public static void Extract(this FileInfo fi, String destDir, Boolean overwrite = false)
```
-��ѹ�ļ���ָ��Ŀ¼��
+解压文件到指定目录。
-**֧�ָ�ʽ**��zip��tar��tar.gz��tgz��7z���� Windows��
+**支持格式**:zip、tar、tar.gz、tgz、7z(仅 Windows)
-**ʾ��**��
+**示例**:
```csharp
-// ��ѹ zip �ļ�
+// 解压 zip 文件
"package.zip".AsFile().Extract("output");
-// ��ѹ tar.gz �ļ�
+// 解压 tar.gz 文件
"archive.tar.gz".AsFile().Extract("output", overwrite: true);
-// Ĭ�Ͻ�ѹ��ͬ��Ŀ¼
-"app.zip".AsFile().Extract(""); // ��ѹ�� app/ Ŀ¼
+// 默认解压到同名目录
+"app.zip".AsFile().Extract(""); // 解压到 app/ 目录
```
-#### Compress���ļ�ѹ����
+#### Compress(文件压缩)
```csharp
public static void Compress(this FileInfo fi, String destFile)
```
-ѹ�������ļ���
+压缩单个文件。
-**ʾ��**��
+**示例**:
```csharp
"large-file.log".AsFile().Compress("large-file.zip");
"data.bin".AsFile().Compress("data.tar.gz");
```
-#### Compress��Ŀ¼ѹ����
+#### Compress(目录压缩)
```csharp
public static void Compress(this DirectoryInfo di, String? destFile = null)
public static void Compress(this DirectoryInfo di, String? destFile, Boolean includeBaseDirectory)
```
-ѹ������Ŀ¼��
+压缩整个目录。
-**ʾ��**��
+**示例**:
```csharp
-// ѹ��Ŀ¼��Ĭ�� zip ��ʽ��
+// 压缩目录(默认 zip 格式)
"src".AsDirectory().Compress("src.zip");
-// ѹ��Ϊ tar.gz
+// 压缩为 tar.gz
"dist".AsDirectory().Compress("dist.tar.gz");
-// ������Ŀ¼����
+// 包含根目录名称
"project".AsDirectory().Compress("project.zip", true);
```
-### �ļ���ϣУ��
+### 文件哈希校验
#### VerifyHash
@@ -377,42 +377,42 @@ public static void Compress(this DirectoryInfo di, String? destFile, Boolean inc
public static Boolean VerifyHash(this FileInfo file, String hash)
```
-��֤�ļ���ϣ�Ƿ�ƥ��Ԥ��ֵ��
+验证文件哈希是否匹配预期值。
-**֧�ֵ��㷨**��
-- MD5��16�32�
+**支持的算法**:
+- MD5(16位或32位)
- SHA1
- SHA256
- SHA512
- CRC32
-**��ϣ��ʽ**��
-- ��ǰ��`md5$abc123...`��`sha256$def456...`��`crc32$12345678`
-- ��ǰ�����ݳ����Զ�ʶ��
- - 8 �ַ���CRC32
- - 16/32 �ַ���MD5
- - 40 �ַ���SHA1
- - 64 �ַ���SHA256
- - 128 �ַ���SHA512
+**哈希格式**:
+- 带前缀:`md5$abc123...`、`sha256$def456...`、`crc32$12345678`
+- 无前缀:根据长度自动识别
+ - 8 字符:CRC32
+ - 16/32 字符:MD5
+ - 40 字符:SHA1
+ - 64 字符:SHA256
+ - 128 字符:SHA512
-**ʾ��**��
+**示例**:
```csharp
var file = "app.exe".AsFile();
-// ���㷨ǰ
+// 带算法前缀
file.VerifyHash("md5$d41d8cd98f00b204e9800998ecf8427e")
file.VerifyHash("sha256$e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
file.VerifyHash("crc32$00000000")
-// ��ǰ���Զ�ʶ��
-file.VerifyHash("d41d8cd98f00b204e9800998ecf8427e") // 32λ -> MD5
-file.VerifyHash("d41d8cd98f00b204") // 16λ -> MD5��ǰ8�ֽڣ�
-file.VerifyHash("12345678") // 8λ -> CRC32
+// 无前缀(自动识别)
+file.VerifyHash("d41d8cd98f00b204e9800998ecf8427e") // 32位 -> MD5
+file.VerifyHash("d41d8cd98f00b204") // 16位 -> MD5(前8字节)
+file.VerifyHash("12345678") // 8位 -> CRC32
```
-## ʹ�ó���
+## 使用场景
-### 1. ���������
+### 1. 配置文件管理
```csharp
public class ConfigManager
@@ -433,7 +433,7 @@ public class ConfigManager
}
```
-### 2. ��־Ŀ¼����
+### 2. 日志目录管理
```csharp
public class LogManager
@@ -448,7 +448,7 @@ public class LogManager
}
```
-### 3. ������������
+### 3. 软件更新与校验
```csharp
public class UpdateManager
@@ -457,17 +457,17 @@ public class UpdateManager
{
var tempFile = Path.GetTempFileName();
- // �����ļ�
+ // 下载文件
await DownloadAsync(url, tempFile);
- // У���ϣ
+ // 校验哈希
if (!tempFile.AsFile().VerifyHash(expectedHash))
{
File.Delete(tempFile);
return false;
}
- // ��ѹ����
+ // 解压更新
tempFile.AsFile().Extract("update_temp", overwrite: true);
return true;
@@ -475,7 +475,7 @@ public class UpdateManager
}
```
-### 4. ��Ŀ����
+### 4. 项目部署
```csharp
public class Deployer
@@ -484,62 +484,62 @@ public class Deployer
{
var source = sourceDir.AsDirectory();
- // �������и��µ��ļ�
+ // 复制所有更新的文件
var updated = source.CopyToIfNewer(targetDir, "*.dll;*.exe;*.json", true, name =>
{
- Console.WriteLine($"����: {name}");
+ Console.WriteLine($"更新: {name}");
});
- Console.WriteLine($"������ {updated.Length} ���ļ�");
+ Console.WriteLine($"共更新 {updated.Length} 个文件");
- // ѹ������
+ // 压缩备份
targetDir.AsDirectory().Compress($"backup_{DateTime.Now:yyyyMMdd}.zip");
}
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ʼ��ʹ�� GetFullPath ����·��
+### 1. 始终使用 GetFullPath 处理路径
```csharp
-// �Ƽ���ʹ����չ������ȡ����·��
+// 推荐:使用扩展方法获取完整路径
var path = "config/app.json".GetFullPath();
-// ���Ƽ���ֱ��ʹ�����·��
-var path = "config/app.json"; // �����ڲ�ͬ��������Ϊ��һ��
+// 不推荐:直接使用相对路径
+var path = "config/app.json"; // 可能在不同环境下行为不一致
```
-### 2. �����ļ�ǰȷ��Ŀ¼����
+### 2. 创建文件前确保目录存在
```csharp
-// �Ƽ�����ȷ��Ŀ¼����
+// 推荐:先确保目录存在
var path = "logs/2024/01/app.log".GetFullPath();
path.EnsureDirectory(true);
File.WriteAllText(path, content);
-// ���Ƽ��������׳� DirectoryNotFoundException
+// 不推荐:可能抛出 DirectoryNotFoundException
File.WriteAllText("logs/2024/01/app.log", content);
```
-### 3. ʹ�� AsFile/AsDirectory ��ʽ����
+### 3. 使用 AsFile/AsDirectory 链式操作
```csharp
-// ������ʽ����
+// 简洁的链式操作
var size = "data.bin".AsFile().ReadBytes().Length;
var files = "src".AsDirectory().GetAllFiles("*.cs", true).Count();
```
-## ƽ̨����
+## 平台差异
-| ���� | Windows | Linux |
+| 功能 | Windows | Linux |
|------|---------|-------|
-| ·���ָ��� | `\` | `/` |
-| 7z ѹ�� | ? ֧�� | ? ��֧�� |
-| tar.gz ѹ�� | .NET 7+ ԭ��֧�� | .NET 7+ ԭ��֧�� |
+| 路径分隔符 | `\` | `/` |
+| 7z 压缩 | ? 支持 | ? 不支持 |
+| tar.gz 压缩 | .NET 7+ 原生支持 | .NET 7+ 原生支持 |
-## �������
+## 相关链接
-- [������չ IOHelper](io_helper-������չIOHelper.md)
-- [ѹ����ѹ��](compression-ѹ����ѹ��.md)
-- [��ȫ��չ SecurityHelper](security_helper-��ȫ��չSecurityHelper.md)
+- [数据扩展 IOHelper](io_helper-数据扩展IOHelper.md)
+- [压缩解压缩](compression-压缩解压缩.md)
+- [安全扩展 SecurityHelper](security_helper-安全扩展SecurityHelper.md)
diff --git "a/Doc/\350\275\273\351\207\217\347\272\247\345\272\224\347\224\250\344\270\273\346\234\272Host.md" "b/Doc/\350\275\273\351\207\217\347\272\247\345\272\224\347\224\250\344\270\273\346\234\272Host.md"
index 331de70..c848014 100644
--- "a/Doc/\350\275\273\351\207\217\347\272\247\345\272\224\347\224\250\344\270\273\346\234\272Host.md"
+++ "b/Doc/\350\275\273\351\207\217\347\272\247\345\272\224\347\224\250\344\270\273\346\234\272Host.md"
@@ -1,55 +1,55 @@
-# ������Ӧ������ Host
+# 轻量级应用主机 Host
-## ����
+## 概述
-`Host` �� NewLife.Core �е�������Ӧ���������ṩӦ�ó����������ڹ������ܡ�֧���йܶ����̨�����Զ�����������ֹͣ�������˳��ȳ������ر��ʺϿ���̨Ӧ�á���̨��������ȳ�����
+`Host` 是 NewLife.Core 中的轻量级应用主机,提供应用程序生命周期管理功能。支持托管多个后台服务,自动处理启动、停止、优雅退出等场景,特别适合控制台应用、后台服务、微服务等场景。
-**�����ռ�**��`NewLife.Model`
-**�ĵ���ַ**��https://newlifex.com/core/host
+**命名空间**:`NewLife.Model`
+**文档地址**:https://newlifex.com/core/host
-## ��������
+## 核心特性
-- **�����й�**��֧��ע�������� `IHostedService` ����
-- **�������ڹ���**���Զ�����������ֹͣ���쳣�ع�
-- **�����˳�**����Ӧ Ctrl+C��SIGINT��SIGTERM ��ϵͳ�ź�
-- **��ƽ̨**��֧�� Windows��Linux��macOS
-- **����ע��**���� `ObjectContainer` ��ȼ���
-- **��ʱ����**��֧�������������ʱ��
+- **服务托管**:支持注册和管理多个 `IHostedService` 服务
+- **生命周期管理**:自动处理启动、停止、异常回滚
+- **优雅退出**:响应 Ctrl+C、SIGINT、SIGTERM 等系统信号
+- **跨平台**:支持 Windows、Linux、macOS
+- **依赖注入**:与 `ObjectContainer` 深度集成
+- **超时控制**:支持设置最大运行时间
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife.Model;
-// ��������
+// 创建主机
var host = new Host(ObjectContainer.Provider);
-// ���Ӻ�̨����
+// 添加后台服务
host.Add<MyBackgroundService>();
host.Add<AnotherService>();
-// ���У�����ֱ���յ��˳��źţ�
+// 运行(阻塞直到收到退出信号)
host.Run();
```
-## API �ο�
+## API 参考
-### IHostedService �ӿ�
+### IHostedService 接口
-��̨�������ʵ�ִ˽ӿڣ�
+后台服务必须实现此接口:
```csharp
public interface IHostedService
{
- /// <summary>��ʼ����</summary>
+ /// <summary>开始服务</summary>
Task StartAsync(CancellationToken cancellationToken);
- /// <summary>ֹͣ����</summary>
+ /// <summary>停止服务</summary>
Task StopAsync(CancellationToken cancellationToken);
}
```
-**ʵ��ʾ��**��
+**实现示例**:
```csharp
public class MyBackgroundService : IHostedService
{
@@ -58,7 +58,7 @@ public class MyBackgroundService : IHostedService
public Task StartAsync(CancellationToken cancellationToken)
{
- XTrace.WriteLine("MyBackgroundService ����");
+ XTrace.WriteLine("MyBackgroundService 启动");
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_task = ExecuteAsync(_cts.Token);
@@ -68,7 +68,7 @@ public class MyBackgroundService : IHostedService
public async Task StopAsync(CancellationToken cancellationToken)
{
- XTrace.WriteLine("MyBackgroundService ֹͣ");
+ XTrace.WriteLine("MyBackgroundService 停止");
_cts?.Cancel();
@@ -80,81 +80,81 @@ public class MyBackgroundService : IHostedService
{
while (!stoppingToken.IsCancellationRequested)
{
- // ִ�к�̨����
- XTrace.WriteLine("��̨����ִ����...");
+ // 执行后台任务
+ XTrace.WriteLine("后台任务执行中...");
await Task.Delay(1000, stoppingToken);
}
}
}
```
-### Host ��
+### Host 类
-#### ���캯��
+#### 构造函数
```csharp
public Host(IServiceProvider serviceProvider)
```
-ͨ�������ṩ�ߴ�������ʵ����
+通过服务提供者创建主机实例。
-**ʾ��**��
+**示例**:
```csharp
-// ʹ��ȫ������
+// 使用全局容器
var host = new Host(ObjectContainer.Provider);
-// ʹ���Զ�������
+// 使用自定义容器
var ioc = new ObjectContainer();
ioc.AddSingleton<ILogger, ConsoleLogger>();
var host = new Host(ioc.BuildServiceProvider());
```
-#### Add - ���ӷ���
+#### Add - 添加服务
```csharp
-// ���ӷ�������
+// 添加服务类型
void Add<TService>() where TService : class, IHostedService
-// ���ӷ���ʵ��
+// 添加服务实例
void Add(IHostedService service)
```
-**ʾ��**��
+**示例**:
```csharp
var host = new Host(ObjectContainer.Provider);
-// ͨ����������
+// 通过类型添加
host.Add<MyBackgroundService>();
host.Add<DataSyncService>();
-// ͨ��ʵ������
+// 通过实例添加
var service = new CustomService(config);
host.Add(service);
```
-#### Run / RunAsync - ��������
+#### Run / RunAsync - 运行主机
```csharp
-// ͬ�����У�������
+// 同步运行(阻塞)
void Run()
-// �첽����
+// 异步运行
Task RunAsync()
```
-�����������������з���Ȼ�������ȴ��˳��źš�
+运行主机,启动所有服务,然后阻塞等待退出信号。
-**ʾ��**��
+**示例**:
```csharp
-// ͬ������
+// 同步运行
host.Run();
-// �첽����
+// 异步运行
await host.RunAsync();
-// �첽���к������������
+// 异步运行后继续其他操作
_ = host.RunAsync();
-// ��������...
+// 其他代码...
```
#### StartAsync / StopAsync
@@ -164,121 +164,121 @@ Task StartAsync(CancellationToken cancellationToken)
Task StopAsync(CancellationToken cancellationToken)
```
-�ֶ�����������ֹͣ��
+手动控制启动和停止。
-**ʾ��**��
+**示例**:
```csharp
using var cts = new CancellationTokenSource();
-// ��������
+// 启动服务
await host.StartAsync(cts.Token);
-// ��һЩ����...
+// 做一些工作...
await Task.Delay(10000);
-// �ֶ�ֹͣ
+// 手动停止
await host.StopAsync(cts.Token);
```
-#### Close - �ر�����
+#### Close - 关闭主机
```csharp
void Close(String? reason)
```
-�����ر�����������ֹͣ���̡�
+主动关闭主机,触发停止流程。
-**ʾ��**��
+**示例**:
```csharp
-// ij�����������ر�
+// 某个条件触发关闭
if (shouldShutdown)
{
- host.Close("���������ر�");
+ host.Close("条件触发关闭");
}
```
-#### MaxTime ����
+#### MaxTime 属性
```csharp
public Int32 MaxTime { get; set; } = -1;
```
-���ִ��ʱ�䣨���룩��Ĭ�� -1 ��ʾ�������С�
+最大执行时间(毫秒)。默认 -1 表示永久运行。
-**ʾ��**��
+**示例**:
```csharp
var host = new Host(ObjectContainer.Provider);
-host.MaxTime = 60_000; // �������60��
+host.MaxTime = 60_000; // 最多运行60秒
host.Add<MyService>();
-host.Run(); // 60����Զ�ֹͣ
+host.Run(); // 60秒后自动停止
```
-### ��̬����
+### 静态方法
-#### RegisterExit - ע���˳��¼�
+#### RegisterExit - 注册退出事件
```csharp
-// ���ܱ���ε���
+// 可能被多次调用
static void RegisterExit(EventHandler onExit)
-// ��ִ��һ��
+// 仅执行一次
static void RegisterExit(Action onExit)
```
-ע��Ӧ���˳�ʱ�Ļص�������
+注册应用退出时的回调函数。
-**ʾ��**��
+**示例**:
```csharp
-// ע���˳���������
+// 注册退出清理函数
Host.RegisterExit(() =>
{
- XTrace.WriteLine("Ӧ�������˳���ִ������...");
+ XTrace.WriteLine("应用正在退出,执行清理...");
CleanupResources();
});
-// �������Ļص�
+// 带参数的回调
Host.RegisterExit((sender, e) =>
{
- XTrace.WriteLine($"�յ��˳��ź�: {sender}");
+ XTrace.WriteLine($"收到退出信号: {sender}");
});
```
-## ��������
+## 容器集成
-### AddHostedService ��չ����
+### AddHostedService 扩展方法
```csharp
-// ͨ������ע��
+// 通过类型注册
IObjectContainer AddHostedService<THostedService>()
-// ͨ������ע��
+// 通过工厂注册
IObjectContainer AddHostedService<THostedService>(
Func<IServiceProvider, THostedService> factory)
```
-**ʾ��**��
+**示例**:
```csharp
var ioc = ObjectContainer.Current;
-// ע���̨����
+// 注册后台服务
ioc.AddHostedService<MyBackgroundService>();
ioc.AddHostedService<DataSyncService>();
-// ʹ�ù���
+// 使用工厂
ioc.AddHostedService(sp =>
{
var config = sp.GetRequiredService<AppConfig>();
return new ConfigurableService(config);
});
-// ��������������
+// 创建主机并运行
var host = new Host(ioc.BuildServiceProvider());
host.Run();
```
-## ʹ�ó���
+## 使用场景
-### 1. ��̨����
+### 1. 简单后台服务
```csharp
class Program
@@ -311,12 +311,12 @@ public class WorkerService : IHostedService
private void DoWork(Object? state)
{
- XTrace.WriteLine($"������... {DateTime.Now}");
+ XTrace.WriteLine($"工作中... {DateTime.Now}");
}
}
```
-### 2. �������
+### 2. 多服务协作
```csharp
class Program
@@ -325,11 +325,11 @@ class Program
{
var ioc = ObjectContainer.Current;
- // ע�Ṳ������
+ // 注册共享依赖
ioc.AddSingleton<IMessageQueue, RedisMessageQueue>();
ioc.AddSingleton<ILogger, FileLogger>();
- // ע������̨����
+ // 注册多个后台服务
ioc.AddHostedService<MessageConsumerService>();
ioc.AddHostedService<HealthCheckService>();
ioc.AddHostedService<MetricsCollectorService>();
@@ -340,7 +340,7 @@ class Program
}
```
-### 3. ��ʱ�������
+### 3. 定时任务服务
```csharp
public class ScheduledTaskService : IHostedService
@@ -355,28 +355,28 @@ public class ScheduledTaskService : IHostedService
public Task StartAsync(CancellationToken cancellationToken)
{
- // ÿ���賿2��ִ��
+ // 每天凌晨2点执行
_timer = new TimerX(ExecuteTask, null, "0 0 2 * * *");
- _logger.Info("��ʱ�������������");
+ _logger.Info("定时任务服务已启动");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Dispose();
- _logger.Info("��ʱ���������ֹͣ");
+ _logger.Info("定时任务服务已停止");
return Task.CompletedTask;
}
private void ExecuteTask(Object? state)
{
- _logger.Info("ִ�ж�ʱ����...");
- // ������
+ _logger.Info("执行定时任务...");
+ // 任务逻辑
}
}
```
-### 4. ����ʱ�IJ�������
+### 4. 带超时的测试运行
```csharp
class Program
@@ -387,16 +387,16 @@ class Program
ioc.AddHostedService<TestService>();
var host = new Host(ioc.BuildServiceProvider());
- host.MaxTime = 30_000; // 30����Զ�ֹͣ
+ host.MaxTime = 30_000; // 30秒后自动停止
await host.RunAsync();
- Console.WriteLine("�������");
+ Console.WriteLine("测试完成");
}
}
```
-### 5. �����˳�����
+### 5. 优雅退出处理
```csharp
public class GracefulService : IHostedService
@@ -408,7 +408,7 @@ public class GracefulService : IHostedService
{
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
- // ���������������
+ // 启动多个工作任务
for (var i = 0; i < 5; i++)
{
_runningTasks.Add(WorkerLoop(i, _cts.Token));
@@ -419,81 +419,81 @@ public class GracefulService : IHostedService
public async Task StopAsync(CancellationToken cancellationToken)
{
- XTrace.WriteLine("�յ�ֹͣ�źţ��ȴ��������...");
+ XTrace.WriteLine("收到停止信号,等待任务完成...");
- // ȡ����������
+ // 取消工作任务
_cts?.Cancel();
- // �ȴ�����������ɣ����ȴ�10��
+ // 等待所有任务完成,最多等待10秒
var timeout = Task.Delay(10_000, cancellationToken);
var allTasks = Task.WhenAll(_runningTasks);
await Task.WhenAny(allTasks, timeout);
- XTrace.WriteLine("����������ֹͣ");
+ XTrace.WriteLine("所有任务已停止");
}
private async Task WorkerLoop(Int32 id, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
- XTrace.WriteLine($"Worker {id} ִ����...");
+ XTrace.WriteLine($"Worker {id} 执行中...");
await Task.Delay(1000, token).ConfigureAwait(false);
}
}
}
```
-## �˳��źŴ���
+## 退出信号处理
-Host �Զ����������˳��źţ�
+Host 自动处理以下退出信号:
-| �ź� | ƽ̨ | ˵�� |
+| 信号 | 平台 | 说明 |
|------|------|------|
-| Ctrl+C | ȫƽ̨ | ����̨�ж� |
-| SIGINT | Linux/macOS | �ж��ź� |
-| SIGTERM | Linux/macOS | ��ֹ�źţ�Docker Ĭ�ϣ� |
-| SIGQUIT | Linux/macOS | �˳��ź� |
-| ProcessExit | ȫƽ̨ | �����˳��¼� |
+| Ctrl+C | 全平台 | 控制台中断 |
+| SIGINT | Linux/macOS | 中断信号 |
+| SIGTERM | Linux/macOS | 终止信号(Docker 默认) |
+| SIGQUIT | Linux/macOS | 退出信号 |
+| ProcessExit | 全平台 | 进程退出事件 |
-**Docker ����ע��**��
+**Docker 部署注意**:
```dockerfile
-# ʹ�� exec ��ʽ��ȷ���ź���ȷ����
+# 使用 exec 形式,确保信号正确传递
CMD ["dotnet", "MyApp.dll"]
-# ����ʹ�� tini ��Ϊ init ����
+# 或者使用 tini 作为 init 进程
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["dotnet", "MyApp.dll"]
```
-## ���ʵ��
+## 最佳实践
-### 1. ��������˳��
+### 1. 服务启动顺序
-����ע��˳��������������˳��ֹͣ��
+服务按注册顺序启动,按反向顺序停止:
```csharp
-ioc.AddHostedService<DatabaseService>(); // ����������ֹͣ
-ioc.AddHostedService<CacheService>(); // �ڶ�
-ioc.AddHostedService<ApiService>(); // ����������ֹͣ
+ioc.AddHostedService<DatabaseService>(); // 先启动,后停止
+ioc.AddHostedService<CacheService>(); // 第二
+ioc.AddHostedService<ApiService>(); // 后启动,先停止
```
-### 2. �쳣����
+### 2. 异常处理
-����ʧ��ʱ���Զ��ع��������ķ���
+启动失败时会自动回滚已启动的服务:
```csharp
public class MyService : IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
- // ����׳��쳣���������ķ���ᱻ�Զ�ֹͣ
+ // 如果抛出异常,已启动的服务会被自动停止
await InitializeAsync();
}
public Task StopAsync(CancellationToken cancellationToken)
{
- // ȷ��ֹͣ�����׳��쳣
+ // 确保停止逻辑不抛出异常
try
{
return CleanupAsync();
@@ -507,9 +507,9 @@ public class MyService : IHostedService
}
```
-### 3. ��Դ�ͷ�
+### 3. 资源释放
-ʵ�� `IDisposable` ���ж���������
+实现 `IDisposable` 进行额外清理:
```csharp
public class ResourceService : IHostedService, IDisposable
@@ -534,8 +534,8 @@ public class ResourceService : IHostedService, IDisposable
}
```
-## �������
+## 相关链接
-- [�������� ObjectContainer](object_container-��������ObjectContainer.md)
-- [����ʱ�� TimerX](timerx-����ʱ��TimerX.md)
-- [��־ϵͳ ILog](log-��־ILog.md)
+- [对象容器 ObjectContainer](object_container-对象容器ObjectContainer.md)
+- [高级定时器 TimerX](timerx-高级定时器TimerX.md)
+- [日志系统 ILog](log-日志ILog.md)
diff --git "a/Doc/\350\277\220\350\241\214\346\227\266\344\277\241\346\201\257Runtime.md" "b/Doc/\350\277\220\350\241\214\346\227\266\344\277\241\346\201\257Runtime.md"
index 6662fb7..0228931 100644
--- "a/Doc/\350\277\220\350\241\214\346\227\266\344\277\241\346\201\257Runtime.md"
+++ "b/Doc/\350\277\220\350\241\214\346\227\266\344\277\241\346\201\257Runtime.md"
@@ -1,52 +1,52 @@
-# ����ʱ��Ϣ Runtime
+# 运行时信息 Runtime
-## ����
+## 概述
-`Runtime` �� NewLife.Core �е�����ʱ��Ϣ�����࣬�ṩ��ǰ���л����ĸ��ּ��Ͳ������ܡ���������ϵͳ�жϡ�����������ȡ���ڴ������������Ϣ�ȹ��ܣ��ǿ�ƽ̨��������Ҫ���������
+`Runtime` 是 NewLife.Core 中的运行时信息工具类,提供当前运行环境的各种检测和操作功能。包括操作系统判断、环境变量读取、内存管理、进程信息等功能,是跨平台开发的重要基础组件。
-**�����ռ�**��`NewLife`
-**�ĵ���ַ**��https://newlifex.com/core/runtime
+**命名空间**:`NewLife`
+**文档地址**:https://newlifex.com/core/runtime
-## ��������
+## 核心特性
-- **ƽ̨���**��Windows��Linux��OSX��Mono��Unity �����л���ʶ��
-- **�����ж�**������̨��Web��������Ӧ�����ͼ��
-- **�߾��ȼ�ʱ**����ƽ̨�� `TickCount64` ʵ�֣����� 32 λ���
-- **�ڴ����**��GC ���պ������ͷ�
-- **��������**�������ִ�Сд�Ļ���������ȡ
+- **平台检测**:Windows、Linux、OSX、Mono、Unity 等运行环境识别
+- **环境判断**:控制台、Web、容器等应用类型检测
+- **高精度计时**:跨平台的 `TickCount64` 实现,避免 32 位溢出
+- **内存管理**:GC 回收和工作集释放
+- **环境变量**:不区分大小写的环境变量读取
-## ���ٿ�ʼ
+## 快速开始
```csharp
using NewLife;
-// �жϲ���ϵͳ
+// 判断操作系统
if (Runtime.Windows)
- Console.WriteLine("������ Windows ϵͳ��");
+ Console.WriteLine("运行在 Windows 系统上");
else if (Runtime.Linux)
- Console.WriteLine("������ Linux ϵͳ��");
+ Console.WriteLine("运行在 Linux 系统上");
-// ������
+// 判断运行环境
if (Runtime.IsConsole)
- Console.WriteLine("����̨Ӧ��");
+ Console.WriteLine("控制台应用");
if (Runtime.Container)
- Console.WriteLine("������������");
+ Console.WriteLine("运行在容器中");
-// ��ȡϵͳ����ʱ�䣨���룩
+// 获取系统运行时间(毫秒)
var uptime = Runtime.TickCount64;
-Console.WriteLine($"ϵͳ������ {uptime / 1000 / 60} ����");
+Console.WriteLine($"系统已运行 {uptime / 1000 / 60} 分钟");
-// ��ȡ��ǰ����ID
+// 获取当前进程ID
var pid = Runtime.ProcessId;
-Console.WriteLine($"��ǰ����ID: {pid}");
+Console.WriteLine($"当前进程ID: {pid}");
-// �ͷ��ڴ�
+// 释放内存
Runtime.FreeMemory();
```
-## API �ο�
+## API 参考
-### ƽ̨���
+### 平台检测
#### Windows
@@ -54,18 +54,18 @@ Runtime.FreeMemory();
public static Boolean Windows { get; }
```
-�Ƿ� Windows ����ϵͳ��
+是否 Windows 操作系统。
-**ʵ�ַ�ʽ**��
-- .NET Core/.NET 5+��ʹ�� `RuntimeInformation.IsOSPlatform(OSPlatform.Windows)`
-- .NET Framework����� `Environment.OSVersion.Platform`
+**实现方式**:
+- .NET Core/.NET 5+:使用 `RuntimeInformation.IsOSPlatform(OSPlatform.Windows)`
+- .NET Framework:检查 `Environment.OSVersion.Platform`
-**ʾ��**��
+**示例**:
```csharp
if (Runtime.Windows)
{
- // Windows ���еIJ���������� Win32 API
- Console.WriteLine("Windows �汾: " + Environment.OSVersion.VersionString);
+ // Windows 特有的操作,如调用 Win32 API
+ Console.WriteLine("Windows 版本: " + Environment.OSVersion.VersionString);
}
```
@@ -75,13 +75,13 @@ if (Runtime.Windows)
public static Boolean Linux { get; }
```
-�Ƿ� Linux ����ϵͳ��
+是否 Linux 操作系统。
-**ʾ��**��
+**示例**:
```csharp
if (Runtime.Linux)
{
- // Linux ���еIJ��������ȡ /proc �ļ�ϵͳ
+ // Linux 特有的操作,如读取 /proc 文件系统
var cpuInfo = File.ReadAllText("/proc/cpuinfo");
}
```
@@ -92,7 +92,7 @@ if (Runtime.Linux)
public static Boolean OSX { get; }
```
-�Ƿ� macOS ����ϵͳ��
+是否 macOS 操作系统。
#### Mono
@@ -100,11 +100,11 @@ public static Boolean OSX { get; }
public static Boolean Mono { get; }
```
-�Ƿ��� Mono ����ʱ���������С�ͨ����� `Mono.Runtime` �����Ƿ�������жϡ�
+是否在 Mono 运行时环境中运行。通过检测 `Mono.Runtime` 类型是否存在来判断。
-**Ӧ�ó���**��
-- ijЩ API �� Mono ����Ϊ��ͬ
-- ��� Mono ���������Ż�����ݴ���
+**应用场景**:
+- 某些 API 在 Mono 下行为不同
+- 针对 Mono 进行特殊优化或兼容处理
#### Unity
@@ -112,9 +112,9 @@ public static Boolean Mono { get; }
public static Boolean Unity { get; }
```
-�Ƿ��� Unity ���滷�������С�ͨ����� `UnityEngine.Application` �����Ƿ�������жϡ�
+是否在 Unity 引擎环境中运行。通过检测 `UnityEngine.Application` 类型是否存在来判断。
-### �����ж�
+### 环境判断
#### IsConsole
@@ -122,30 +122,30 @@ public static Boolean Unity { get; }
public static Boolean IsConsole { get; set; }
```
-�Ƿ����̨Ӧ�ó���
+是否控制台应用程序。
-**���**��
-1. ���Է��� `Console.ForegroundColor` ��������̨�����Լ��
-2. ��鵱ǰ�����Ƿ��������ھ��
-3. �κ��쳣����Ϊ�ǿ���̨����
+**判断逻辑**:
+1. 尝试访问 `Console.ForegroundColor` 触发控制台可用性检查
+2. 检查当前进程是否有主窗口句柄
+3. 任何异常都视为非控制台环境
-**ʾ��**��
+**示例**:
```csharp
if (Runtime.IsConsole)
{
- Console.WriteLine("���ǿ���̨Ӧ�ã�����ʹ�ò�ɫ���");
+ Console.WriteLine("这是控制台应用,可以使用彩色输出");
Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine("��ɫ�ı�");
+ Console.WriteLine("绿色文本");
Console.ResetColor();
}
else
{
- // GUI Ӧ�û����
- Debug.WriteLine("�ǿ���̨����");
+ // GUI 应用或服务
+ Debug.WriteLine("非控制台环境");
}
```
-> **ע��**������ͨ������ `Runtime.IsConsole = false` ǿ�ƽ��ÿ���̨�жϡ�
+> **注意**:可以通过设置 `Runtime.IsConsole = false` 强制禁用控制台判断。
#### Container
@@ -153,14 +153,14 @@ else
public static Boolean Container { get; }
```
-�Ƿ��� Docker/Kubernetes ���������С�ͨ����黷������ `DOTNET_RUNNING_IN_CONTAINER` ���жϡ�
+是否在 Docker/Kubernetes 容器中运行。通过检查环境变量 `DOTNET_RUNNING_IN_CONTAINER` 来判断。
-**ʾ��**��
+**示例**:
```csharp
if (Runtime.Container)
{
- // ���������µ������
- // ���磺ʹ�������ڵ�����·��
+ // 容器环境下的特殊处理
+ // 例如:使用容器内的配置路径
var configPath = "/app/config";
}
```
@@ -171,22 +171,22 @@ if (Runtime.Container)
public static Boolean IsWeb { get; }
```
-�Ƿ� Web Ӧ�ó���
+是否 Web 应用程序。
-**���**��
-- .NET Core/.NET 5+������Ƿ������ `Microsoft.AspNetCore` ����
-- .NET Framework����� `System.Web.HttpRuntime.AppDomainAppId` �Ƿ���ֵ
+**判断逻辑**:
+- .NET Core/.NET 5+:检查是否加载了 `Microsoft.AspNetCore` 程序集
+- .NET Framework:检查 `System.Web.HttpRuntime.AppDomainAppId` 是否有值
-**ʾ��**��
+**示例**:
```csharp
if (Runtime.IsWeb)
{
- // Web Ӧ�����еĴ���
- // ���磺ʹ�� HTTP ��������ع���
+ // Web 应用特有的处理
+ // 例如:使用 HTTP 上下文相关功能
}
```
-### ʱ�������
+### 时间与计数
#### TickCount64
@@ -194,28 +194,28 @@ if (Runtime.IsWeb)
public static Int64 TickCount64 { get; }
```
-ϵͳ���������ĺ�������64λ�������ᷢ�� 32 λ������⡣
+系统启动以来的毫秒数(64位),不会发生 32 位溢出问题。
-**ʵ�ַ�ʽ**��
-- .NET Core 3.1+��ֱ��ʹ�� `Environment.TickCount64`
-- Windows �ɿ�ܣ����� `GetTickCount64` Win32 API
-- ����ƽ̨��ʹ�� `Stopwatch.GetTimestamp()` ���㣬����˵� `Environment.TickCount`
+**实现方式**:
+- .NET Core 3.1+:直接使用 `Environment.TickCount64`
+- Windows 旧框架:调用 `GetTickCount64` Win32 API
+- 其他平台:使用 `Stopwatch.GetTimestamp()` 计算,或回退到 `Environment.TickCount`
-**Ӧ�ó���**��
-- �߾��ȼ�ʱ
-- ����ʱ����
-- ���� `Environment.TickCount` Լ 49.7 �����������
+**应用场景**:
+- 高精度计时
+- 计算时间间隔
+- 避免 `Environment.TickCount` 约 49.7 天溢出的问题
-**ʾ��**��
+**示例**:
```csharp
-// ����������ʱ
+// 测量操作耗时
var start = Runtime.TickCount64;
DoSomeWork();
var elapsed = Runtime.TickCount64 - start;
-Console.WriteLine($"��ʱ: {elapsed} ms");
+Console.WriteLine($"耗时: {elapsed} ms");
-// ���ó�ʱ
-var timeout = Runtime.TickCount64 + 5000; // 5���ʱ
+// 设置超时
+var timeout = Runtime.TickCount64 + 5000; // 5秒后超时
while (Runtime.TickCount64 < timeout)
{
if (CheckCondition()) break;
@@ -229,16 +229,16 @@ while (Runtime.TickCount64 < timeout)
public static DateTimeOffset UtcNow { get; }
```
-��ȡ��ǰ UTC ʱ�䡣����ȫ��ʱ���ṩ�ߣ�`TimerScheduler.GlobalTimeProvider`�������dz�Ӧ���л����η�����ʱ��
+获取当前 UTC 时间。基于全局时间提供者(`TimerScheduler.GlobalTimeProvider`),在星尘应用中会屏蔽服务器时间差。
-**ʾ��**��
+**示例**:
```csharp
var utcNow = Runtime.UtcNow;
-Console.WriteLine($"UTCʱ��: {utcNow}");
-Console.WriteLine($"����ʱ��: {utcNow.LocalDateTime}");
+Console.WriteLine($"UTC时间: {utcNow}");
+Console.WriteLine($"本地时间: {utcNow.LocalDateTime}");
```
-### ������Ϣ
+### 进程信息
#### ProcessId
@@ -246,17 +246,17 @@ Console.WriteLine($"
public static Int32 ProcessId { get; }
```
-��ǰ���� ID��ʹ�û�������ظ���ȡ��
+当前进程 ID。使用缓存避免重复获取。
-**ʵ�ַ�ʽ**��
-- .NET 5+��ʹ�� `Environment.ProcessId`
-- �ɿ�ܣ�ʹ�� `Process.GetCurrentProcess().Id`
+**实现方式**:
+- .NET 5+:使用 `Environment.ProcessId`
+- 旧框架:使用 `Process.GetCurrentProcess().Id`
-**ʾ��**��
+**示例**:
```csharp
-Console.WriteLine($"��ǰ����ID: {Runtime.ProcessId}");
+Console.WriteLine($"当前进程ID: {Runtime.ProcessId}");
-// ������־��¼
+// 用于日志记录
var logPrefix = $"[PID:{Runtime.ProcessId}]";
```
@@ -266,18 +266,18 @@ var logPrefix = $"[PID:{Runtime.ProcessId}]";
public static String ClientId { get; }
```
-�ͻ��˱�ʶ����ʽΪ `ip@pid`�����ڷֲ�ʽϵͳ�б�ʶ�ͻ���ʵ����
+客户端标识,格式为 `ip@pid`。用于分布式系统中标识客户端实例。
-**ʾ��**��
+**示例**:
```csharp
-Console.WriteLine($"�ͻ��˱�ʶ: {Runtime.ClientId}");
-// �������: 192.168.1.100@12345
+Console.WriteLine($"客户端标识: {Runtime.ClientId}");
+// 输出类似: 192.168.1.100@12345
-// ���ڷֲ�ʽ������Ϣ���������߱�ʶ��
+// 用于分布式锁、消息队列消费者标识等
var consumerId = Runtime.ClientId;
```
-### ��������
+### 环境变量
#### GetEnvironmentVariable
@@ -285,15 +285,15 @@ var consumerId = Runtime.ClientId;
public static String? GetEnvironmentVariable(String variable)
```
-��ȡ����������**�����ִ�Сд**��
+获取环境变量,**不区分大小写**。
-**�ص�**��
-- �ȳ��Ծ�ȷƥ��
-- ��δ�ҵ����������л����������в����ִ�Сд�ıȽ�
+**特点**:
+- 先尝试精确匹配
+- 若未找到,遍历所有环境变量进行不区分大小写的比较
-**ʾ��**��
+**示例**:
```csharp
-// �����ִ�Сд��ȡ��������
+// 不区分大小写获取环境变量
var path = Runtime.GetEnvironmentVariable("PATH");
var home = Runtime.GetEnvironmentVariable("HOME");
var customVar = Runtime.GetEnvironmentVariable("MY_APP_CONFIG");
@@ -305,9 +305,9 @@ var customVar = Runtime.GetEnvironmentVariable("MY_APP_CONFIG");
public static IDictionary<String, String?> GetEnvironmentVariables()
```
-��ȡ���л������������ز����ִ�Сд���ֵ䡣
+获取所有环境变量,返回不区分大小写的字典。
-**ʾ��**��
+**示例**:
```csharp
var envVars = Runtime.GetEnvironmentVariables();
foreach (var kv in envVars.Where(e => e.Key.StartsWith("DOTNET")))
@@ -316,7 +316,7 @@ foreach (var kv in envVars.Where(e => e.Key.StartsWith("DOTNET")))
}
```
-### ����
+### 配置
#### CreateConfigOnMissing
@@ -324,19 +324,19 @@ foreach (var kv in envVars.Where(e => e.Key.StartsWith("DOTNET")))
public static Boolean CreateConfigOnMissing { get; set; }
```
-�����ļ�������ʱ���Ƿ�����Ĭ�������ļ���Ĭ��Ϊ `true`��
+配置文件不存在时,是否生成默认配置文件。默认为 `true`。
-**���÷�ʽ**��
-- ����������`CreateConfigOnMissing=false`
-- �������ã�`Runtime.CreateConfigOnMissing = false`
+**配置方式**:
+- 环境变量:`CreateConfigOnMissing=false`
+- 代码设置:`Runtime.CreateConfigOnMissing = false`
-**ʾ��**��
+**示例**:
```csharp
-// ����������ֹ�Զ����������ļ�
+// 生产环境禁止自动创建配置文件
Runtime.CreateConfigOnMissing = false;
```
-### �ڴ����
+### 内存管理
#### FreeMemory
@@ -344,39 +344,39 @@ Runtime.CreateConfigOnMissing = false;
public static Boolean FreeMemory(Int32 processId = 0, Boolean gc = true, Boolean workingSet = true)
```
-�ͷ��ڴ档ִ�� GC ���ղ��ͷŹ�������Windows����
+释放内存。执行 GC 回收并释放工作集(Windows)。
-**����˵��**��
-- `processId`��Ŀ�����ID��0 ��ʾ��ǰ����
-- `gc`���Ƿ�ִ�� GC ���գ�����ǰ������Ч��
-- `workingSet`���Ƿ��ͷŹ��������� Windows ��Ч��
+**参数说明**:
+- `processId`:目标进程ID,0 表示当前进程
+- `gc`:是否执行 GC 回收(仅当前进程有效)
+- `workingSet`:是否释放工作集(仅 Windows 有效)
-**ִ�в���**��
-1. ִ�� `GC.Collect` ������������
-2. ���� `GC.WaitForPendingFinalizers` �ȴ��ս���
-3. �ٴ�ִ�� `GC.Collect`
-4. ���� `EmptyWorkingSet` �ͷŹ�������Windows��
+**执行步骤**:
+1. 执行 `GC.Collect` 进行垃圾回收
+2. 调用 `GC.WaitForPendingFinalizers` 等待终结器
+3. 再次执行 `GC.Collect`
+4. 调用 `EmptyWorkingSet` 释放工作集(Windows)
-**ʾ��**��
+**示例**:
```csharp
-// �����ͷ��ڴ�
+// 定期释放内存
var timer = new TimerX(state =>
{
Runtime.FreeMemory();
-}, null, 60_000, 60_000); // ÿ����ִ��һ��
+}, null, 60_000, 60_000); // 每分钟执行一次
-// ���ͷŹ�������������GC
+// 仅释放工作集,不触发GC
Runtime.FreeMemory(gc: false);
-// �ͷ�ָ�����̵��ڴ�
+// 释放指定进程的内存
Runtime.FreeMemory(processId: 1234, gc: false);
```
-> **ע��**��Ƶ������ `FreeMemory` ����Ӱ�����ܣ��������ڴ�ѹ���ϴ�ʱ���ڵ��á�
+> **注意**:频繁调用 `FreeMemory` 可能影响性能,建议在内存压力较大时定期调用。
-## ʹ�ó���
+## 使用场景
-### 1. ��ƽ̨·������
+### 1. 跨平台路径处理
```csharp
public String GetConfigPath()
@@ -392,21 +392,21 @@ public String GetConfigPath()
}
```
-### 2. ������������
+### 2. 容器环境适配
```csharp
public void ConfigureServices()
{
if (Runtime.Container)
{
- // �����������ӻ���������ȡ����
+ // 容器环境:从环境变量读取配置
var connStr = Runtime.GetEnvironmentVariable("DATABASE_URL");
services.AddDbContext<MyDbContext>(options =>
options.UseNpgsql(connStr));
}
else
{
- // ���ؿ������������ļ���ȡ
+ // 本地开发:从配置文件读取
var connStr = Configuration.GetConnectionString("Default");
services.AddDbContext<MyDbContext>(options =>
options.UseNpgsql(connStr));
@@ -414,7 +414,7 @@ public void ConfigureServices()
}
```
-### 3. �ڴ������ͷ�
+### 3. 内存监控与释放
```csharp
public class MemoryMonitor
@@ -432,14 +432,14 @@ public class MemoryMonitor
var gcMemory = GC.GetTotalMemory(false);
if (gcMemory > MemoryThreshold)
{
- XTrace.WriteLine($"�ڴ泬����ֵ ({gcMemory / 1024 / 1024}MB)����ʼ�ͷ�");
+ XTrace.WriteLine($"内存超过阈值 ({gcMemory / 1024 / 1024}MB),开始释放");
Runtime.FreeMemory();
}
}
}
```
-### 4. ���ܼ�ʱ��
+### 4. 性能计时器
```csharp
public class PerformanceTimer : IDisposable
@@ -456,23 +456,23 @@ public class PerformanceTimer : IDisposable
public void Dispose()
{
var elapsed = Runtime.TickCount64 - _startTime;
- XTrace.WriteLine($"{_operation} ��ʱ: {elapsed}ms");
+ XTrace.WriteLine($"{_operation} 耗时: {elapsed}ms");
}
}
-// ʹ��
-using (new PerformanceTimer("���ݿ��ѯ"))
+// 使用
+using (new PerformanceTimer("数据库查询"))
{
var result = db.Query<User>().ToList();
}
```
-## ���ʵ��
+## 最佳实践
-### 1. ƽ̨�ض��������
+### 1. 平台特定代码隔离
```csharp
-// �Ƽ���ʹ�������жϸ���ƽ̨�ض�����
+// 推荐:使用条件判断隔离平台特定代码
public void DoWork()
{
if (Runtime.Windows)
@@ -484,40 +484,40 @@ public void DoWork()
}
```
-### 2. ����Ƶ������ FreeMemory
+### 2. 避免频繁调用 FreeMemory
```csharp
-// ���Ƽ���ÿ�β������ͷ�
+// 不推荐:每次操作后都释放
foreach (var item in items)
{
ProcessItem(item);
- Runtime.FreeMemory(); // ����ɱ�֣�
+ Runtime.FreeMemory(); // 性能杀手!
}
-// �Ƽ��������������ͷţ���ʱ�ͷ�
+// 推荐:批量处理后释放,或定时释放
foreach (var item in items)
{
ProcessItem(item);
}
-Runtime.FreeMemory(); // ������ɺ�ͳһ�ͷ�
+Runtime.FreeMemory(); // 处理完成后统一释放
```
-### 3. ʹ�� TickCount64 ���� DateTime ��ʱ
+### 3. 使用 TickCount64 而非 DateTime 计时
```csharp
-// ���Ƽ���DateTime ��ʱ������ϵͳʱ�����Ӱ��
+// 不推荐:DateTime 计时可能受系统时间调整影响
var start = DateTime.Now;
DoWork();
var elapsed = (DateTime.Now - start).TotalMilliseconds;
-// �Ƽ���TickCount64 ����ϵͳʱ��Ӱ��
+// 推荐:TickCount64 不受系统时间影响
var start = Runtime.TickCount64;
DoWork();
var elapsed = Runtime.TickCount64 - start;
```
-## �������
+## 相关链接
-- [������Ϣ MachineInfo](machine_info-������ϢMachineInfo.md)
-- [��־ϵͳ ILog](log-��־ILog.md)
-- [����ʱ�� TimerX](timerx-����ʱ��TimerX.md)
+- [机器信息 MachineInfo](machine_info-机器信息MachineInfo.md)
+- [日志系统 ILog](log-日志ILog.md)
+- [高级定时器 TimerX](timerx-高级定时器TimerX.md)
diff --git "a/Doc/\351\205\215\347\275\256\346\217\220\344\276\233\350\200\205IConfigProvider.md" "b/Doc/\351\205\215\347\275\256\346\217\220\344\276\233\350\200\205IConfigProvider.md"
index efd623c..6d92ad8 100644
--- "a/Doc/\351\205\215\347\275\256\346\217\220\344\276\233\350\200\205IConfigProvider.md"
+++ "b/Doc/\351\205\215\347\275\256\346\217\220\344\276\233\350\200\205IConfigProvider.md"
@@ -1,108 +1,108 @@
-# IConfigProvider ������ϵʹ��˵��
-
-���ĵ����� NewLife.Configuration ������ϵ�ļܹ����÷�����չ�㣬������ NewLife.Core �ֿ⡣
-
-## 1. �ܹ�����
-
-- ���ij���
- - `IConfigProvider`�������ṩ��ͳһ�ӿڣ���¶��ֵ���ʡ����ζη��ʡ�ģ�� Load/Save/Bind�����֪ͨ��
- - `IConfigSection`�����öΣ��ڵ㣩����/ֵ/ע�����Ӽ������Σ��ṹ��
- - `GetConfigCallback`����ȡ���õ�ί�У�������ע�뵽����ģ���н��а�����ȡ��
-- �������
- - `ConfigProvider`��ʵ�� `IConfigProvider` �Ļ��࣬�ṩ�����ء���·�����ʡ�ģ��ӳ�䡢������֪ͨ��Ĭ���ṩ��ע���빤��������
- - `FileConfigProvider`���ļ����ṩ���࣬��װ�ļ���д����ѯ�ȼ��أ�`TimerX`����
-- ����ʵ��
- - `XmlConfigProvider`��XML ���
- - `InIConfigProvider`��INI ���
- - `JsonConfigProvider`��JSON �ļ���֧��ע�͵�Ԥ��������
- - `HttpConfigProvider`���������ģ��dz��ȣ��������ػ��桢�汾�������ϱ���֧�ֶ�ʱˢ�¡�
- - `ApolloConfigProvider`����� Apollo �����䣨�����ռ�ۺ϶�ȡ����
- - `CompositeConfigProvider`�������ṩ�ߣ��ۺ϶���ṩ�ߣ���ȡ���ȡ�����������ԡ�
-- �������
- - `Config<T>`������ģ�ͻ��࣬`Current` ͨ����ע `ConfigAttribute` �Զ�ѡ���ṩ�߲�����/��
- - `ConfigHelper`����ģ����������֮�����ӳ�䣨`MapTo/MapFrom`����֧�����顢`IList<T>`�����Ӷ����ֵ䡣
- - `IConfigMapping`���Զ���ӳ��ӿڣ��û�����ģ����ʵ���Ի����ȫ���Ƶ�ӳ������
-
-## 2. �����÷�
-
-- �����
+# IConfigProvider 配置体系使用说明
+
+本文档介绍 NewLife.Configuration 配置体系的架构、用法与扩展点,适用于 NewLife.Core 仓库。
+
+## 1. 架构概览
+
+- 核心抽象
+ - `IConfigProvider`:配置提供者统一接口,暴露键值访问、树形段访问、模型 Load/Save/Bind、变更通知。
+ - `IConfigSection`:配置段(节点),键/值/注释与子级(树形)结构。
+ - `GetConfigCallback`:获取配置的委托,可用于注入到其它模块中进行按键获取。
+- 抽象基类
+ - `ConfigProvider`:实现 `IConfigProvider` 的基类,提供懒加载、键路径访问、模型映射、绑定与变更通知、默认提供者注册与工厂方法。
+ - `FileConfigProvider`:文件型提供者基类,封装文件读写、轮询热加载(`TimerX`)。
+- 具体实现
+ - `XmlConfigProvider`:XML 文件。
+ - `InIConfigProvider`:INI 文件。
+ - `JsonConfigProvider`:JSON 文件(支持注释的预处理)。
+ - `HttpConfigProvider`:配置中心(星尘等),带本地缓存、版本与增量上报,支持定时刷新。
+ - `ApolloConfigProvider`:针对 Apollo 的适配(命名空间聚合读取)。
+ - `CompositeConfigProvider`:复合提供者,聚合多个提供者,读取优先、保存逐个尝试。
+- 辅助与模型
+ - `Config<T>`:配置模型基类,`Current` 通过标注 `ConfigAttribute` 自动选择提供者并加载/绑定。
+ - `ConfigHelper`:在模型与配置树之间进行映射(`MapTo/MapFrom`),支持数组、`IList<T>`、复杂对象、字典。
+ - `IConfigMapping`:自定义映射接口,用户可在模型中实现以获得完全控制的映射逻辑。
+
+## 2. 典型用法
+
+- 定义模型
```csharp
-[Config("core", provider: null)] // ʹ��Ĭ���ṩ�ߣ���ȫ���л���
+[Config("core", provider: null)] // 使用默认提供者(可全局切换)
public class CoreConfig : Config<CoreConfig>
{
- [Description("ȫ�ֵ��ԡ�XTrace.Debug")] public bool Debug { get; set; }
+ [Description("全局调试。XTrace.Debug")] public bool Debug { get; set; }
public string? LogPath { get; set; }
public SysConfig Sys { get; set; } = new();
}
public class SysConfig
{
- [Description("���ڱ�ʶϵͳ��Ӣ�����������пո�")] public string Name { get; set; } = "";
+ [Description("用于标识系统的英文名,不能有空格")] public string Name { get; set; } = "";
public string? DisplayName { get; set; }
}
```
-- ����/����
+- 加载/保存
```csharp
-var cfg = CoreConfig.Current; // �״λ���Զ����̣����½���
+var cfg = CoreConfig.Current; // 首次会绑定并自动落盘(若新建)
cfg.Debug = true;
cfg.Save();
```
-- ֱ��ʹ���ṩ��
+- 直接使用提供者
```csharp
-var prv = ConfigProvider.Create("config")!; // xml Ĭ�� .config
+var prv = ConfigProvider.Create("config")!; // xml 默认 .config
prv.Init("core");
prv.LoadAll();
-var debug = prv["Debug"]; // ��·��֧��ð�ŷָ���"Sys:Name"
+var debug = prv["Debug"]; // 键路径支持冒号分隔:"Sys:Name"
var section = prv.GetSection("Sys:Name");
```
-- ���ȸ���
+- 绑定热更新
```csharp
var cfg = new CoreConfig();
var prv = new JsonConfigProvider { FileName = "Config/core.json" };
-prv.Bind(cfg, autoReload: true); // �ļ����/Զ�����ͽ�ˢ�� cfg
+prv.Bind(cfg, autoReload: true); // 文件变更/远端推送将刷新 cfg
```
-- �����ṩ��
+- 复合提供者
```csharp
var local = new JsonConfigProvider { FileName = "Config/appsettings.json" };
var remote = new HttpConfigProvider { Server = "http://conf", AppId = "Demo" };
var composite = new CompositeConfigProvider(local, remote);
-var name = composite["Sys:Name"]; // ��ȡʱ��˳�����
+var name = composite["Sys:Name"]; // 读取时按顺序查找
```
-## 3. ��չ��
+## 3. 扩展点
-- �½��ļ��ṩ�ߣ��̳� `FileConfigProvider`����д `OnRead` �� `GetString/OnWrite` ���ɡ�
-- �½�Զ���ṩ�ߣ��̳� `ConfigProvider`��ʵ�� `LoadAll/SaveAll` �붨ʱˢ�£���ѡ����
-- ע��ΪĬ�ϣ�`ConfigProvider.Register<MyProvider>("my");`�����ͨ�� `ConfigProvider.Create("my")` ʹ�á�
+- 新建文件提供者:继承 `FileConfigProvider`,重写 `OnRead` 与 `GetString/OnWrite` 即可。
+- 新建远端提供者:继承 `ConfigProvider`,实现 `LoadAll/SaveAll` 与定时刷新(可选)。
+- 注册为默认:`ConfigProvider.Register<MyProvider>("my");`,随后通过 `ConfigProvider.Create("my")` 使用。
-## 4. ��Ϊ��Լ��
+## 4. 行为与约定
-- ��·�����`A:B:C` ��ʾ�������ꡣ
-- `Keys` Ĭ��ֻ���ظ��µ�һ���������ʵ�ֿɸ��Ƿ����������ϡ�
-- `IsNew` ����ָʾ����Դ�Ƿ��״δ�����`Config<T>.Current` ��ݴ˾����Ƿ�־û�Ĭ��ֵ��
-- ע�ͣ�ģ�������ϵ� `DescriptionAttribute/DisplayNameAttribute` ��д��������ע�͡�
-- �б������飺`ConfigHelper` ֧�� `T[]` �� `IList<T>`����Ԫ����Ԫ�ػ��������ת����
+- 键路径语法:`A:B:C` 表示树形下钻。
+- `Keys` 默认只返回根下第一层键;具体实现可覆盖返回深层键集合。
+- `IsNew` 用于指示配置源是否首次创建,`Config<T>.Current` 会据此决定是否持久化默认值。
+- 注释:模型属性上的 `DescriptionAttribute/DisplayNameAttribute` 会写入配置项注释。
+- 列表与数组:`ConfigHelper` 支持 `T[]` 与 `IList<T>`;基元类型元素会进行类型转换。
-## 5. ���ֿ��Ż��㣨�Ѵ�����
+## 5. 本仓库优化点(已处理)
-- ����`ConfigHelper.MapToList` �Ի�Ԫ����Ԫ�ؽ��� `ChangeType` ת�������� `List<int>` ��д���ַ����б���
-- ��׳�ԣ�`ConfigProvider.Keys` ����ǰ���� `EnsureLoad()`������δ���ؼ����ʵ��µĿռ������С�
-- ������ȫ��`ConfigProvider` �İ��ϸ�Ϊ `ConcurrentDictionary`����ֹ���֪ͨ�ڼ�ö���쳣��
+- 修复:`ConfigHelper.MapToList` 对基元类型元素进行 `ChangeType` 转换,避免 `List<int>` 被写成字符串列表。
+- 健壮性:`ConfigProvider.Keys` 访问前调用 `EnsureLoad()`,避免未加载即访问导致的空集合误判。
+- 并发安全:`ConfigProvider` 的绑定集合改为 `ConcurrentDictionary`,防止变更通知期间枚举异常。
-## 6. ע������
+## 6. 注意事项
-- ���ܣ�����������ӳ�䲻Ӧ�����ȵ��Ƶ·��������Ƶ�����ʣ��뻺�����û�ʹ��ǿ���Ͱ�
-- �̰߳�ȫ��ģ�Ͱ���ˢ�»ص���Ҫִ�к�ʱ��������������֪ͨ��·��
-- �����ԣ���� .NET Framework �� .NET Standard �������䣬����ʹ��ƽ̨ר�� API��
+- 性能:反射与树形映射不应放在热点高频路径;如需频繁访问,请缓存配置或使用强类型绑定。
+- 线程安全:模型绑定与刷新回调不要执行耗时操作,避免阻塞通知链路。
+- 兼容性:针对 .NET Framework 与 .NET Standard 均已适配,无需使用平台专属 API。
---
-���ϡ�
+以上。
diff --git "a/Doc/\351\205\215\347\275\256\347\263\273\347\273\237Config.md" "b/Doc/\351\205\215\347\275\256\347\263\273\347\273\237Config.md"
index 4b4b4d6..dced64f 100644
--- "a/Doc/\351\205\215\347\275\256\347\263\273\347\273\237Config.md"
+++ "b/Doc/\351\205\215\347\275\256\347\263\273\347\273\237Config.md"
@@ -1,158 +1,158 @@
-# ����ϵͳ Config
+# 配置系统 Config
-## ����
+## 概述
-NewLife.Core �ṩ��ǿ����������ϵͳ��֧�� XML��JSON��INI �ȶ��ָ�ʽ���Լ������ļ���Զ���������ġ�ͨ�� `Config<T>` ������Կ��ٴ���ǿ�������ã�֧���ȸ��º��Զ����档
+NewLife.Core 提供了强大灵活的配置系统,支持 XML、JSON、INI 等多种格式,以及本地文件和远程配置中心。通过 `Config<T>` 基类可以快速创建强类型配置,支持热更新和自动保存。
-**�����ռ�**��`NewLife.Configuration`
-**�ĵ���ַ**��https://newlifex.com/core/config
+**命名空间**:`NewLife.Configuration`
+**文档地址**:https://newlifex.com/core/config
-## ��������
+## 核心特性
-- **ǿ��������**���̳� `Config<T>` �Զ����������ļ�
-- **���ʽ֧��**��XML��JSON��INI��HTTP �������ṩ��
-- **�ȸ���**�������ļ��仯ʱ�Զ�����
-- **ע��֧��**��XML ��ʽ֧���Զ�����ע��
-- **�ֲ�����**��֧�ֶ༶Ƕ�����ýṹ
-- **��������**��֧��Զ���������ģ����dz���
+- **强类型配置**:继承 `Config<T>` 自动管理配置文件
+- **多格式支持**:XML、JSON、INI、HTTP 等配置提供者
+- **热更新**:配置文件变化时自动重载
+- **注释支持**:XML 格式支持自动生成注释
+- **分层配置**:支持多级嵌套配置结构
+- **配置中心**:支持远程配置中心(如星尘)
-## ���ٿ�ʼ
+## 快速开始
-### ����������
+### 定义配置类
```csharp
using NewLife.Configuration;
using System.ComponentModel;
-/// <summary>Ӧ������</summary>
-[Config("App")] // �����ļ���Ϊ App.config
+/// <summary>应用配置</summary>
+[Config("App")] // 配置文件名为 App.config
public class AppConfig : Config<AppConfig>
{
- [Description("Ӧ������")]
+ [Description("应用名称")]
public String Name { get; set; } = "MyApp";
- [Description("����˿�")]
+ [Description("服务端口")]
public Int32 Port { get; set; } = 8080;
- [Description("����ģʽ")]
+ [Description("调试模式")]
public Boolean Debug { get; set; }
- [Description("���ݿ�����")]
+ [Description("数据库连接")]
public String ConnectionString { get; set; } = "Server=.;Database=test";
}
```
-### ʹ������
+### 使用配置
```csharp
-// ��ȡ���ã��Զ�����/���������ļ���
+// 读取配置(自动加载/创建配置文件)
var config = AppConfig.Current;
-Console.WriteLine($"Ӧ��: {config.Name}");
-Console.WriteLine($"�˿�: {config.Port}");
+Console.WriteLine($"应用: {config.Name}");
+Console.WriteLine($"端口: {config.Port}");
-// �IJ�����
+// 修改并保存
config.Debug = true;
config.Save();
```
-**�Զ����ɵ������ļ�** (`App.config`)��
+**自动生成的配置文件** (`App.config`):
```xml
<?xml version="1.0" encoding="utf-8"?>
<App>
- <!--Ӧ������-->
+ <!--应用名称-->
<Name>MyApp</Name>
- <!--����˿�-->
+ <!--服务端口-->
<Port>8080</Port>
- <!--����ģʽ-->
+ <!--调试模式-->
<Debug>false</Debug>
- <!--���ݿ�����-->
+ <!--数据库连接-->
<ConnectionString>Server=.;Database=test</ConnectionString>
</App>
```
-## API �ο�
+## API 参考
-### Config<T> ����
+### Config<T> 基类
```csharp
public class Config<TConfig> where TConfig : Config<TConfig>, new()
{
- /// <summary>��ǰʹ�õ��ṩ��</summary>
+ /// <summary>当前使用的提供者</summary>
public static IConfigProvider? Provider { get; set; }
- /// <summary>��ǰʵ��</summary>
+ /// <summary>当前实例</summary>
public static TConfig Current { get; }
- /// <summary>��������</summary>
+ /// <summary>加载配置</summary>
public virtual Boolean Load();
- /// <summary>��������</summary>
+ /// <summary>保存配置</summary>
public virtual Boolean Save();
- /// <summary>���ü��غ�</summary>
+ /// <summary>配置加载后触发</summary>
protected virtual void OnLoaded() { }
}
```
-### ConfigAttribute ����
+### ConfigAttribute 特性
```csharp
[AttributeUsage(AttributeTargets.Class)]
public class ConfigAttribute : Attribute
{
- /// <summary>���������ļ�����������չ����</summary>
+ /// <summary>配置名(文件名,不含扩展名)</summary>
public String Name { get; set; }
- /// <summary>�����ṩ������</summary>
+ /// <summary>配置提供者类型</summary>
public Type? Provider { get; set; }
}
```
-### IConfigProvider �ӿ�
+### IConfigProvider 接口
```csharp
public interface IConfigProvider
{
- /// <summary>����</summary>
+ /// <summary>名称</summary>
String Name { get; set; }
- /// <summary>��Ԫ��</summary>
+ /// <summary>根元素</summary>
IConfigSection Root { get; set; }
- /// <summary>�Ƿ�������</summary>
+ /// <summary>是否新配置</summary>
Boolean IsNew { get; set; }
- /// <summary>��ȡ/��������ֵ</summary>
+ /// <summary>获取/设置配置值</summary>
String? this[String key] { get; set; }
- /// <summary>��������</summary>
+ /// <summary>加载配置</summary>
Boolean LoadAll();
- /// <summary>��������</summary>
+ /// <summary>保存配置</summary>
Boolean SaveAll();
- /// <summary>���ص�ģ��</summary>
+ /// <summary>加载到模型</summary>
T? Load<T>(String? path = null) where T : new();
- /// <summary>��ģ�ͣ��ȸ��£�</summary>
+ /// <summary>绑定模型(热更新)</summary>
void Bind<T>(T model, Boolean autoReload = true, String? path = null);
- /// <summary>���øı��¼�</summary>
+ /// <summary>配置改变事件</summary>
event EventHandler? Changed;
}
```
-## �����ṩ��
+## 配置提供者
-### XmlConfigProvider��Ĭ�ϣ�
+### XmlConfigProvider(默认)
```csharp
-// �Զ�ʹ�� XML ��ʽ
+// 自动使用 XML 格式
[Config("Database")]
public class DbConfig : Config<DbConfig> { }
-// ����ʽָ��
+// 或显式指定
[Config("Database", Provider = typeof(XmlConfigProvider))]
public class DbConfig : Config<DbConfig> { }
```
@@ -174,7 +174,7 @@ public class LoggingConfig
}
```
-**���ɵ� JSON �ļ�**��
+**生成的 JSON 文件**:
```json
{
"Name": "MyApp",
@@ -198,7 +198,7 @@ public class IniConfig : Config<IniConfig>
### HttpConfigProvider
-��������Զ���������ģ�
+用于连接远程配置中心:
```csharp
[HttpConfig("http://config.server.com", AppId = "myapp", Secret = "xxx")]
@@ -208,33 +208,33 @@ public class RemoteConfig : Config<RemoteConfig>
}
```
-## ʹ�ó���
+## 使用场景
-### 1. ���ݿ�����
+### 1. 数据库配置
```csharp
[Config("Database")]
public class DatabaseConfig : Config<DatabaseConfig>
{
- [Description("���ݿ�����")]
+ [Description("数据库类型")]
public String DbType { get; set; } = "MySql";
- [Description("�����ַ���")]
+ [Description("连接字符串")]
public String ConnectionString { get; set; }
- [Description("���������")]
+ [Description("最大连接数")]
public Int32 MaxPoolSize { get; set; } = 100;
- [Description("���ʱ���룩")]
+ [Description("命令超时(秒)")]
public Int32 CommandTimeout { get; set; } = 30;
}
-// ʹ��
+// 使用
var db = DatabaseConfig.Current;
var connStr = db.ConnectionString;
```
-### 2. Ƕ������
+### 2. 嵌套配置
```csharp
[Config("Service")]
@@ -259,7 +259,7 @@ public class CacheConfig
}
```
-### 3. ��������
+### 3. 数组配置
```csharp
[Config("Servers")]
@@ -276,7 +276,7 @@ public class EndpointConfig
}
```
-### 4. ������֤
+### 4. 配置验证
```csharp
[Config("App")]
@@ -286,125 +286,125 @@ public class AppConfig : Config<AppConfig>
protected override void OnLoaded()
{
- // ��֤����
+ // 验证配置
if (Port <= 0 || Port > 65535)
{
Port = 8080;
- XTrace.WriteLine("�˿�������Ч��ʹ��Ĭ��ֵ 8080");
+ XTrace.WriteLine("端口配置无效,使用默认值 8080");
}
}
}
```
-### 5. �������
+### 5. 配置变更监听
```csharp
var config = AppConfig.Current;
AppConfig.Provider.Changed += (s, e) =>
{
- XTrace.WriteLine("�����Ѹ���");
- // ���¶�ȡ����
+ XTrace.WriteLine("配置已更新");
+ // 重新读取配置
config = AppConfig.Current;
};
```
-### 6. ֱ��ʹ���ṩ��
+### 6. 直接使用提供者
```csharp
-// ���̳� Config<T>��ֱ��ʹ���ṩ��
+// 不继承 Config<T>,直接使用提供者
var provider = new JsonConfigProvider { FileName = "custom.json" };
provider.LoadAll();
-// ��ȡֵ
+// 读取值
var name = provider["Name"];
var port = provider["Server:Port"].ToInt();
-// ����ֵ
+// 设置值
provider["Debug"] = "true";
provider.SaveAll();
```
-## ��������
+## 配置文件路径
-Ĭ�������ļ������Ӧ�ó���Ŀ¼����ͨ�����·�ʽ�Զ��壺
+默认配置文件存放在应用程序目录,可通过以下方式自定义:
```csharp
-// ���·��
+// 相对路径
[Config("Config/App")]
public class AppConfig : Config<AppConfig> { }
-// �����ṩ�߳�ʼ��
+// 配置提供者初始化
var provider = new XmlConfigProvider();
provider.Init("Config/App.config");
```
-## ���ʵ��
+## 最佳实践
-### 1. ʹ�� Description ����
+### 1. 使用 Description 特性
```csharp
-[Description("��־����Debug/Info/Warn/Error")]
+[Description("日志级别:Debug/Info/Warn/Error")]
public String LogLevel { get; set; } = "Info";
```
-### 2. �ṩĬ��ֵ
+### 2. 提供默认值
```csharp
public Int32 MaxRetry { get; set; } = 3;
public String[] AllowedHosts { get; set; } = ["*"];
```
-### 3. ������Ϣ����
+### 3. 敏感信息处理
```csharp
[Config("Secrets")]
public class SecretsConfig : Config<SecretsConfig>
{
- // ����ӻ���������ȡ
+ // 建议从环境变量读取
public String ApiKey { get; set; } =
Environment.GetEnvironmentVariable("API_KEY") ?? "";
}
```
-### 4. ��������
+### 4. 配置重载
```csharp
-// ǿ�����¼�������
+// 强制重新加载配置
AppConfig._Current = null;
var fresh = AppConfig.Current;
```
-## �� appsettings.json ����
+## 与 appsettings.json 集成
```csharp
-// ���� ASP.NET Core ��������
+// 加载 ASP.NET Core 风格的配置
var provider = JsonConfigProvider.LoadAppSettings();
var connectionString = provider["ConnectionStrings:Default"];
var logLevel = provider["Logging:LogLevel:Default"];
```
-## ���ü̳�
+## 配置继承
```csharp
public abstract class BaseConfig<T> : Config<T> where T : BaseConfig<T>, new()
{
- [Description("Ӧ�ð汾")]
+ [Description("应用版本")]
public String Version { get; set; } = "1.0.0";
- [Description("���õ���")]
+ [Description("启用调试")]
public Boolean Debug { get; set; }
}
[Config("MyApp")]
public class MyAppConfig : BaseConfig<MyAppConfig>
{
- [Description("�ض�����")]
+ [Description("特定设置")]
public String CustomSetting { get; set; }
}
```
-## �������
+## 相关链接
-- [JSON ���л�](json-JSON���л�.md)
-- [XML ���л�](xml-XML���л�.md)
-- [��־ϵͳ ILog](log-��־ILog.md)
+- [JSON 序列化](json-JSON序列化.md)
+- [XML 序列化](xml-XML序列化.md)
+- [日志系统 ILog](log-日志ILog.md)
diff --git "a/Doc/\351\223\276\350\267\257\350\277\275\350\270\252ITracer.md" "b/Doc/\351\223\276\350\267\257\350\277\275\350\270\252ITracer.md"
index e87e606..2ff63c6 100644
--- "a/Doc/\351\223\276\350\267\257\350\277\275\350\270\252ITracer.md"
+++ "b/Doc/\351\223\276\350\267\257\350\277\275\350\270\252ITracer.md"
@@ -1,39 +1,39 @@
-# ��·��ITracer
+# 链路追踪ITracer
-## ����
+## 概述
-�ɹ۲����Ǻ����ִ�Ӧ�������ĺ���ָ��֮һ��NewLife.Core �ṩ��һ����������·�ٹ淶��`ITracer`/`ISpan`������ʵ�������� APM��Application Performance Monitoring����
+可观测性是衡量现代应用质量的核心指标之一。NewLife.Core 提供了一套完整的链路追踪规范:`ITracer`/`ISpan`,用于实现轻量级 APM(Application Performance Monitoring)。
-�봫ͳ APM ϵͳ��ͬ��NewLife ����·�ٲ���**���ز���+ͳ��**�ķ�ʽ��
-- �ڱ���������ݲ����ͳ���ͳ��
-- ���ϱ�ͳ�����ݺ�������������
-- �����ʡ���紫��ʹ洢�ɱ�
+与传统 APM 系统不同,NewLife 的链路追踪采用**本地采样+统计**的方式:
+- 在本地完成数据采样和初步统计
+- 仅上报统计数据和少量采样样本
+- 极大节省网络传输和存储成本
-NewLife ȫϵ����Ŀ��30+ ������������� `ITracer` ��㣬�����߿��ԣ�
-1. ������ػ�ȡ�������ָ��
-2. �����dz����ƽ̨ʵ�ֲַ�ʽ��
-3. ���ڹ淶��չ�Զ������
+NewLife 全系列项目(30+ 组件)均内置了 `ITracer` 埋点,开发者可以:
+1. 无侵入地获取组件运行指标
+2. 接入星尘监控平台实现分布式追踪
+3. 基于规范扩展自定义埋点
-**Nuget ��**: `NewLife.Core`
-**Դ��**: [NewLife.Core/Log/ITracer.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Log/ITracer.cs)
+**Nuget 包**: `NewLife.Core`
+**源码**: [NewLife.Core/Log/ITracer.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Log/ITracer.cs)
---
-## ��������
+## 快速入门
-### �����÷�
+### 基础用法
-������ʾ����
+最简单的埋点示例:
```csharp
-using var span = tracer?.NewSpan("��������");
+using var span = tracer?.NewSpan("操作名称");
```
-ʹ�� `using` �ؼ���ȷ�� span �����������ʱ�Զ���ɣ���¼��ʱ�ʹ�����
+使用 `using` 关键字确保 span 在作用域结束时自动完成,记录耗时和次数。
-### ����ʾ��
+### 完整示例
-����������������ݵ����ʾ����
+以下是网络接收数据的埋点示例:
```csharp
private void Ss_Received(Object? sender, ReceivedEventArgs e)
@@ -41,7 +41,7 @@ private void Ss_Received(Object? sender, ReceivedEventArgs e)
var ns = (this as INetSession).Host;
var tracer = ns?.Tracer;
- // ������㣬��¼���ղ���
+ // 创建埋点,记录接收操作
using var span = tracer?.NewSpan($"net:{ns?.Name}:Receive", e.Message);
try
{
@@ -49,182 +49,182 @@ private void Ss_Received(Object? sender, ReceivedEventArgs e)
}
catch (Exception ex)
{
- // ��Ǵ���¼�쳣��Ϣ
+ // 标记错误并记录异常信息
span?.SetError(ex, e.Message ?? e.Packet);
throw;
}
}
```
-���ʾ����ʾ�ˣ�
-- **�������**��ʹ�ö�̬���ɵ�����
-- **���ݱ�ǩ**���ڶ������� `e.Message` ��Ϊ���ݱ�ǩ
-- **�쳣����**��ͨ�� `SetError` ����쳣���
-- **�Զ���¼**��`using` ����Զ���¼��ʱ
+这个示例演示了:
+- **创建埋点**:使用动态生成的名称
+- **数据标签**:第二个参数 `e.Message` 作为数据标签
+- **异常处理**:通过 `SetError` 标记异常埋点
+- **自动记录**:`using` 语句自动记录耗时
-ͨ�������㣬���ǿ��ԣ�
-- ͳ�ƽ������ݰ��Ĵ���
-- ��¼ÿ�ν��յĺ�ʱ
-- ͳ���쳣��������
-- �鿴�������ݺͱ�ǩ
+通过这个埋点,我们可以:
+- 统计接收数据包的次数
+- 记录每次接收的耗时
+- 统计异常发生次数
+- 查看采样数据和标签
---
-## ���Ľӿ�
+## 核心接口
-### ITracer �ӿ�
+### ITracer 接口
-���ܸ������������� APM �淶�ĺ��Ľӿڡ�
+性能跟踪器,轻量级 APM 规范的核心接口。
```csharp
public interface ITracer
{
- #region ����
- /// <summary>�������ڡ���λ�룬Ĭ��15��</summary>
+ #region 属性
+ /// <summary>采样周期。单位秒,默认15秒</summary>
Int32 Period { get; set; }
- /// <summary>������������������������ڣ����ֻ��¼ָ�������������¼���Ĭ��1</summary>
+ /// <summary>最大正常采样数。采样周期内,最多只记录指定数量的正常事件,默认1</summary>
Int32 MaxSamples { get; set; }
- /// <summary>����쳣�����������������ڣ����ֻ��¼ָ���������쳣�¼���Ĭ��10</summary>
+ /// <summary>最大异常采样数。采样周期内,最多只记录指定数量的异常事件,默认10</summary>
Int32 MaxErrors { get; set; }
- /// <summary>��ʱʱ�䡣������ʱ��ʱǿ�Ʋ�������λ���룬Ĭ��5000</summary>
+ /// <summary>超时时间。超过该时间时强制采样,单位毫秒,默认5000</summary>
Int32 Timeout { get; set; }
- /// <summary>����ǩ���ȡ������ó���ʱ���ضϣ�Ĭ��1024�ַ�</summary>
+ /// <summary>最大标签长度。超过该长度时将截断,默认1024字符</summary>
Int32 MaxTagLength { get; set; }
- /// <summary>��http/rpc����ע��TraceId�IJ�������Ϊ�ձ�ʾ��ע�룬Ĭ��W3C����traceparent</summary>
+ /// <summary>向http/rpc请求注入TraceId的参数名,为空表示不注入,默认W3C标准的traceparent</summary>
String? AttachParameter { get; set; }
#endregion
- /// <summary>����Span������</summary>
- /// <param name="name">�������ƣ����ڱ�ʶ��ͬ���������</param>
+ /// <summary>建立Span构建器</summary>
+ /// <param name="name">操作名称,用于标识不同的埋点类型</param>
ISpanBuilder BuildSpan(String name);
- /// <summary>��ʼһ��Span</summary>
- /// <param name="name">�������ƣ����ڱ�ʶ��ͬ���������</param>
+ /// <summary>开始一个Span</summary>
+ /// <param name="name">操作名称,用于标识不同的埋点类型</param>
ISpan NewSpan(String name);
- /// <summary>��ʼһ��Span��ָ�����ݱ�ǩ</summary>
- /// <param name="name">�������ƣ����ڱ�ʶ��ͬ���������</param>
- /// <param name="tag">���ݱ�ǩ����¼�ؼ�������Ϣ</param>
+ /// <summary>开始一个Span,指定数据标签</summary>
+ /// <param name="name">操作名称,用于标识不同的埋点类型</param>
+ /// <param name="tag">数据标签,记录关键参数信息</param>
ISpan NewSpan(String name, Object? tag);
- /// <summary>�ض�����Span���������ݣ����ü���</summary>
+ /// <summary>截断所有Span构建器数据,重置集合</summary>
ISpanBuilder[] TakeAll();
}
```
-#### �ؼ�����˵��
+#### 关键属性说明
-| ���� | Ĭ��ֵ | ˵�� |
+| 属性 | 默认值 | 说明 |
|-----|-------|------|
-| `Period` | 15�� | �������ڣ������ϱ����ݵ�ʱ���� |
-| `MaxSamples` | 1 | ÿ�������ڼ�¼�����������������ڻ��Ƶ���������ϵ |
-| `MaxErrors` | 10 | ÿ�������ڼ�¼���쳣������������������� |
-| `Timeout` | 5000ms | ��ʱ��ֵ��������ʱ��IJ����ᱻǿ�Ʋ��� |
-| `MaxTagLength` | 1024 | ��ǩ��ȣ������ᱻ�ض� |
-| `AttachParameter` | "traceparent" | HTTP/RPC ������ע�� TraceId �IJ���������ѭ W3C �� |
+| `Period` | 15秒 | 采样周期,定期上报数据的时间间隔 |
+| `MaxSamples` | 1 | 每个周期内记录的正常采样数,用于绘制调用依赖关系 |
+| `MaxErrors` | 10 | 每个周期内记录的异常采样数,用于问题诊断 |
+| `Timeout` | 5000ms | 超时阈值,超过此时间的操作会被强制采样 |
+| `MaxTagLength` | 1024 | 标签最大长度,超过会被截断 |
+| `AttachParameter` | "traceparent" | HTTP/RPC 请求中注入 TraceId 的参数名,遵循 W3C 标准 |
-��Щ����ͨ�����dz�������Ķ�̬�·������������ֶ����á�
+这些参数通常由星尘监控中心动态下发调整,无需手动配置。
-#### �����
+#### 核心方法
-- **`NewSpan(String name)`**: ��õķ���������һ�������
-- **`NewSpan(String name, Object? tag)`**: ������㲢�������ݱ�ǩ
-- **`BuildSpan(String name)`**: ��ȡ�� SpanBuilder�����ڸ�����
+- **`NewSpan(String name)`**: 最常用的方法,创建一个新埋点
+- **`NewSpan(String name, Object? tag)`**: 创建埋点并附加数据标签
+- **`BuildSpan(String name)`**: 获取或创建 SpanBuilder,用于高级场景
-### ISpan �ӿ�
+### ISpan 接口
-���ܸ���Ƭ�Σ�����һ����������ʵ����
+性能跟踪片段,代表一个具体的埋点实例。
```csharp
public interface ISpan : IDisposable
{
- /// <summary>Ψһ��ʶ�����߳������ġ�Http��Rpc���ݣ���Ϊ�ڲ�Ƭ�εĸ���</summary>
+ /// <summary>唯一标识。随线程上下文、Http、Rpc传递,作为内部片段的父级</summary>
String Id { get; set; }
- /// <summary>����������ڱ�ʶ��ͬ���͵IJ���</summary>
+ /// <summary>埋点名。用于标识不同类型的操作</summary>
String Name { get; set; }
- /// <summary>����Ƭ�α�ʶ�����ڹ���������</summary>
+ /// <summary>父级片段标识。用于构建调用链</summary>
String? ParentId { get; set; }
- /// <summary>���ٱ�ʶ�������ڹ������Ƭ�Σ�����������ϵ�����߳������ġ�Http��Rpc����</summary>
+ /// <summary>跟踪标识。可用于关联多个片段,建立依赖关系,随线程上下文、Http、Rpc传递</summary>
String TraceId { get; set; }
- /// <summary>��ʼʱ�䡣Unix����ʱ���</summary>
+ /// <summary>开始时间。Unix毫秒时间戳</summary>
Int64 StartTime { get; set; }
- /// <summary>����ʱ�䡣Unix����ʱ���</summary>
+ /// <summary>结束时间。Unix毫秒时间戳</summary>
Int64 EndTime { get; set; }
- /// <summary>�û���ֵ����¼�����ͱ�������ÿ�����ݿ�����������dz�ƽ̨����ͳ��</summary>
+ /// <summary>用户数值。记录数字型标量,如每次数据库操作行数,星尘平台汇总统计</summary>
Int64 Value { get; set; }
- /// <summary>���ݱ�ǩ����¼һЩ�������ݣ��������������Ӧ�����</summary>
+ /// <summary>数据标签。记录一些附加数据,如请求参数、响应结果等</summary>
String? Tag { get; set; }
- /// <summary>������Ϣ����¼�쳣��Ϣ</summary>
+ /// <summary>错误信息。记录异常消息</summary>
String? Error { get; set; }
- /// <summary>���ô�����Ϣ��ApiException����</summary>
+ /// <summary>设置错误信息,ApiException除外</summary>
void SetError(Exception ex, Object? tag = null);
- /// <summary>�������ݱ�ǩ���ڲ�������Ƚض�</summary>
+ /// <summary>设置数据标签。内部根据最大长度截断</summary>
void SetTag(Object tag);
- /// <summary>������㣬������ɼ�</summary>
+ /// <summary>抛弃埋点,不计入采集</summary>
void Abandon();
}
```
-#### �ؼ�����
+#### 关键属性
-| ���� | ���� | ˵�� |
+| 属性 | 类型 | 说明 |
|-----|------|------|
-| `Id` | String | Span Ψһ��ʶ����ѭ W3C �� |
-| `ParentId` | String? | ���� Span ID�����ڹ��������� |
-| `TraceId` | String | ��������ʶ��ͬһ�������е����� Span ������ͬ TraceId |
-| `StartTime` | Int64 | ��ʼʱ�䣨Unix ���룩 |
-| `EndTime` | Int64 | ����ʱ�䣨Unix ���룩 |
-| `Value` | Int64 | �û���ֵ���ɼ�¼ҵ��ָ�꣨�����ݿ������� |
-| `Tag` | String? | ���ݱ�ǩ����¼�����������Ӧ���ݵ� |
-| `Error` | String? | ������Ϣ |
+| `Id` | String | Span 唯一标识,遵循 W3C 标准 |
+| `ParentId` | String? | 父级 Span ID,用于构建调用树 |
+| `TraceId` | String | 跟踪链标识,同一调用链中的所有 Span 共享相同 TraceId |
+| `StartTime` | Int64 | 开始时间(Unix 毫秒) |
+| `EndTime` | Int64 | 结束时间(Unix 毫秒) |
+| `Value` | Int64 | 用户数值,可记录业务指标(如数据库行数) |
+| `Tag` | String? | 数据标签,记录请求参数、响应数据等 |
+| `Error` | String? | 错误信息 |
-#### �����
+#### 核心方法
-- **`SetError(Exception ex, Object? tag)`**: ����쳣��`ApiException` ���ͻᱻ�����
-- **`SetTag(Object tag)`**: �������ݱ�ǩ��֧�ֶ��������Զ����л�
-- **`Abandon()`**: ������ǰ��㣬�����ڹ�����Ч������404ɨ�裩
+- **`SetError(Exception ex, Object? tag)`**: 标记异常,`ApiException` 类型会被特殊处理
+- **`SetTag(Object tag)`**: 设置数据标签,支持多种类型自动序列化
+- **`Abandon()`**: 丢弃当前埋点,常用于过滤无效请求(如404扫描)
---
-## ʹ�����ʵ��
+## 使用最佳实践
-### 1. ע�� ITracer
+### 1. 注入 ITracer
-�� ASP.NET Core Ӧ���У�ͨ���dz���չע�룺
+在 ASP.NET Core 应用中,通过星尘扩展注入:
```csharp
using NewLife.Stardust.Extensions;
var builder = WebApplication.CreateBuilder(args);
-// ע���dz������� ITracer ʵ��
+// 注入星尘,包含 ITracer 实现
builder.Services.AddStardust();
```
-�����[�dz��ֲ�ʽ����ƽ̨](https://newlifex.com/blood/stardust)
+详见:[星尘分布式服务平台](https://newlifex.com/blood/stardust)
-### 2. ��ȡ ITracer ʵ��
+### 2. 获取 ITracer 实例
-�ж��ַ�ʽ��ȡ `ITracer`��
+有多种方式获取 `ITracer`:
```csharp
-// ��ʽ1�����캯��ע�루�Ƽ���
+// 方式1:构造函数注入(推荐)
public class MyService
{
private readonly ITracer _tracer;
@@ -235,58 +235,58 @@ public class MyService
}
}
-// ��ʽ2������ע��
+// 方式2:属性注入
public class MyService
{
public ITracer? Tracer { get; set; }
}
-// ��ʽ3��ʹ��ȫ�־�̬ʵ��
+// 方式3:使用全局静态实例
var tracer = DefaultTracer.Instance;
```
-### 3. �������
+### 3. 创建埋点
-#### �������
+#### 基础埋点
```csharp
using var span = _tracer?.NewSpan("MyOperation");
-// ҵ����
+// 业务逻辑
```
-#### �����ݱ�ǩ�����
+#### 带数据标签的埋点
```csharp
var request = new { UserId = 123, Action = "Query" };
using var span = _tracer?.NewSpan("UserQuery", request);
-// ҵ����
+// 业务逻辑
```
-#### ���쳣���������
+#### 带异常处理的埋点
```csharp
using var span = _tracer?.NewSpan("DatabaseQuery");
try
{
- // ִ�����ݿ��ѯ
+ // 执行数据库查询
var result = await ExecuteQueryAsync();
}
catch (Exception ex)
{
- span?.SetError(ex, "��ѯʧ��");
+ span?.SetError(ex, "查询失败");
throw;
}
```
-#### ��¼ҵ��ָ��
+#### 记录业务指标
```csharp
using var span = _tracer?.NewSpan("BatchProcess");
var count = ProcessRecords();
-span.Value = count; // ��¼�����ļ�¼��
+span.Value = count; // 记录处理的记录数
```
-### 4. ��ʱ�������ʾ��
+### 4. 定时任务埋点示例
```csharp
public class DataRetentionService : IHostedService
@@ -303,7 +303,7 @@ public class DataRetentionService : IHostedService
public Task StartAsync(CancellationToken cancellationToken)
{
- // ÿ600��ִ��һ�Σ�����ӳ�����
+ // 每600秒执行一次,随机延迟启动
_timer = new TimerX(DoWork, null,
DateTime.Today.AddMinutes(Rand.Next(60)),
600 * 1000)
@@ -323,16 +323,16 @@ public class DataRetentionService : IHostedService
var time2 = DateTime.Now.AddDays(-set.DataRetention2);
var time3 = DateTime.Now.AddDays(-set.DataRetention3);
- // ������㣬��¼��������
+ // 创建埋点,记录清理任务
using var span = _tracer?.NewSpan("DataRetention", new { time, time2, time3 });
try
{
- // ɾ��������
+ // 删除旧数据
var rs = AppMinuteStat.DeleteBefore(time);
- XTrace.WriteLine("ɾ��[{0}]֮ǰ��AppMinuteStat����{1:n0}", time, rs);
+ XTrace.WriteLine("删除[{0}]之前的AppMinuteStat共:{1:n0}", time, rs);
rs = TraceMinuteStat.DeleteBefore(time);
- XTrace.WriteLine("ɾ��[{0}]֮ǰ��TraceMinuteStat����{1:n0}", time, rs);
+ XTrace.WriteLine("删除[{0}]之前的TraceMinuteStat共:{1:n0}", time, rs);
}
catch (Exception ex)
{
@@ -348,141 +348,141 @@ public class DataRetentionService : IHostedService
}
```
-### 5. ����������
+### 5. 过滤无效请求
-�� Web Ӧ���У�������������ɨ��������ʹ�� `Abandon()` ������Щ��㣺
+在 Web 应用中,经常遇到各种扫描请求,可以使用 `Abandon()` 丢弃这些埋点:
```csharp
public IActionResult ProcessRequest()
{
using var span = _tracer?.NewSpan("WebRequest");
- // ����Ч������404ɨ�裩
+ // 检测到无效请求(如404扫描)
if (IsInvalidScan())
{
- span?.Abandon(); // ������㣬������ͳ��
+ span?.Abandon(); // 丢弃埋点,不计入统计
return NotFound();
}
- // ��������
+ // 正常处理
return Ok();
}
```
---
-## �ֲ�ʽ��·��
+## 分布式链路追踪
-### �����
+### 跨服务传递
-ISpan �ṩ����չ������֧��ͨ�� HTTP/RPC ���ݸ��������ģ�
+ISpan 提供了扩展方法,支持通过 HTTP/RPC 传递跟踪上下文:
```csharp
-// HTTP ����ע��
+// HTTP 请求注入
var request = new HttpRequestMessage(HttpMethod.Get, url);
-span?.Attach(request); // ע�� traceparent ͷ
+span?.Attach(request); // 注入 traceparent 头
await httpClient.SendAsync(request);
-// RPC ����ע��
+// RPC 调用注入
var args = new { UserId = 123 };
-span?.Attach(args); // ע����ٲ���
+span?.Attach(args); // 注入跟踪参数
await rpcClient.InvokeAsync("Method", args);
```
-������յ�������Զ����� `traceparent` �������ָ����������ġ�
+服务端收到请求后,会自动解析 `traceparent` 参数,恢复跟踪上下文。
-### ����������
+### 调用链构建
-ͬһ�� `TraceId` �µ����� Span ���Զ��γɵ�������
+同一个 `TraceId` 下的所有 Span 会自动形成调用链:
```
TraceId: ac1b1e8617342790000015eb0ea2a6
-���� DataRetention (��)
- ���� SQL:AppMinuteStat.DeleteBefore (��)
- ���� SQL:TraceMinuteStat.DeleteBefore (��)
- ���� SQL:TraceHourStat.DeleteBefore (��)
+├─ DataRetention (父)
+ ├─ SQL:AppMinuteStat.DeleteBefore (子)
+ ├─ SQL:TraceMinuteStat.DeleteBefore (子)
+ └─ SQL:TraceHourStat.DeleteBefore (子)
```
-���dz����ƽ̨���Բ鿴��
-- [����������ͼ](https://star.newlifex.com/trace?id=ac1b1e8617342790000015eb0ea2a6)
-- [��������־��ͼ](https://star.newlifex.com/trace?id=ac1b1e8617342790000015eb0ea2a6&layout=detail)
+在星尘监控平台可以查看:
+- [调用链火焰图](https://star.newlifex.com/trace?id=ac1b1e8617342790000015eb0ea2a6)
+- [调用链日志视图](https://star.newlifex.com/trace?id=ac1b1e8617342790000015eb0ea2a6&layout=detail)
---
-## ��������
+## 监控与分析
-### �鿴ͳ������
+### 查看统计数据
-���dz����ƽ̨���Բ鿴���ͳ�ƣ�
-- �����ܴ���
-- �쳣����
-- ƽ����ʱ������ʱ����С��ʱ
-- QPS��ÿ����������
+在星尘监控平台可以查看埋点统计:
+- 调用总次数
+- 异常次数
+- 平均耗时、最大耗时、最小耗时
+- QPS(每秒请求数)
-ʾ����[DataRetention ���ͳ��](https://star.newlifex.com/Monitors/traceDayStat?appId=4&itemId=284)
+示例:[DataRetention 埋点统计](https://star.newlifex.com/Monitors/traceDayStat?appId=4&itemId=284)
-### ��������
+### 采样策略
-ITracer �������ܲ������ԣ�
-1. **��������**��ÿ����������ౣ�� `MaxSamples` ������������Ĭ��1����
-2. **�쳣����**��ÿ����������ౣ�� `MaxErrors` ���쳣������Ĭ��10����
-3. **��ʱ����**����ʱ���� `Timeout` �IJ���ǿ�Ʋ���
-4. **ȫ��·����**������ `TraceFlag` �ĵ�����ȫ������
+ITracer 采用智能采样策略:
+1. **正常采样**:每个周期内最多保留 `MaxSamples` 个正常样本(默认1个)
+2. **异常采样**:每个周期内最多保留 `MaxErrors` 个异常样本(默认10个)
+3. **超时采样**:耗时超过 `Timeout` 的操作强制采样
+4. **全链路采样**:设置 `TraceFlag` 的调用链全量采样
-### ����ͳ�ƻ���
+### 本地统计机制
-ÿ���������Ӧһ�� `SpanBuilder`�������ۼ�ͳ�ƣ�
-- **Total**: �ܴ���
-- **Errors**: �쳣����
-- **Cost**: �ܺ�ʱ
-- **MaxCost**: ����ʱ
-- **MinCost**: ��С��ʱ
+每个埋点名对应一个 `SpanBuilder`,用于累加统计:
+- **Total**: 总次数
+- **Errors**: 异常次数
+- **Cost**: 总耗时
+- **MaxCost**: 最大耗时
+- **MinCost**: 最小耗时
-ÿ���������ڽ�����`SpanBuilder` ���ݴ���ϱ���Ȼ�����ü�������
+每个采样周期结束后,`SpanBuilder` 数据打包上报,然后重置计数器。
---
-## ������
+## 高级特性
-### ��������淶
+### 埋点命名规范
-����ʹ�÷ֲ����������ڷ���ͳ�ƣ�
+建议使用分层命名,便于分类统计:
```csharp
-// �����
-tracer.NewSpan("net:{��}:Receive");
+// 网络层
+tracer.NewSpan("net:{协议}:Receive");
tracer.NewSpan("net:tcp:Send");
-// ���ݿ��
-tracer.NewSpan("db:{����}:Select");
+// 数据库层
+tracer.NewSpan("db:{表名}:Select");
tracer.NewSpan("db:User:Insert");
-// ҵ���
-tracer.NewSpan("biz:{�}:{����}");
+// 业务层
+tracer.NewSpan("biz:{模块}:{操作}");
tracer.NewSpan("biz:Order:Create");
-// �ⲿ����
-tracer.NewSpan("http:{����}:{����}");
+// 外部调用
+tracer.NewSpan("http:{服务}:{方法}");
tracer.NewSpan("http:PaymentApi:Pay");
```
-### ��̬��������
+### 动态参数调整
-���Զ�̬��������������
+可以动态调整采样参数:
```csharp
var tracer = DefaultTracer.Instance;
-tracer.Period = 30; // ��Ϊ30������
-tracer.MaxSamples = 5; // ��������������
-tracer.Timeout = 10000; // ��ʱ��ֵ��Ϊ10��
-tracer.MaxTagLength = 2048; // ��ǩ���ȸ�Ϊ2K
+tracer.Period = 30; // 改为30秒周期
+tracer.MaxSamples = 5; // 增加正常采样数
+tracer.Timeout = 10000; // 超时阈值改为10秒
+tracer.MaxTagLength = 2048; // 标签长度改为2K
```
-ͨ����Щ�������dz��������ͳһ�·���
+通常这些参数由星尘监控中心统一下发。
-### �Զ��� ITracer ʵ��
+### 自定义 ITracer 实现
-����ʵ���Լ��� `ITracer`��
+可以实现自己的 `ITracer`:
```csharp
public class CustomTracer : ITracer
@@ -490,51 +490,51 @@ public class CustomTracer : ITracer
public Int32 Period { get; set; } = 15;
public Int32 MaxSamples { get; set; } = 1;
public Int32 MaxErrors { get; set; } = 10;
- // ... ʵ�ֽӿڷ���
+ // ... 实现接口方法
public ISpan NewSpan(String name)
{
- // �Զ�����㴴����
+ // 自定义埋点创建逻辑
var span = new CustomSpan { Name = name };
span.Start();
return span;
}
}
-// ע���Զ���ʵ��
+// 注册自定义实现
DefaultTracer.Instance = new CustomTracer();
```
---
-## ������
+## 性能优化
-### �����
+### 对象池
-`DefaultTracer` �����˶���أ����� `ISpanBuilder` �� `ISpan` ʵ����
+`DefaultTracer` 内置了对象池,复用 `ISpanBuilder` 和 `ISpan` 实例:
```csharp
public IPool<ISpanBuilder> BuilderPool { get; }
public IPool<ISpan> SpanPool { get; }
```
-Ƶ����������������Զ��黹����أ����� GC ѹ����
+频繁创建的埋点对象会自动归还对象池,减少 GC 压力。
-### ��ǩ���ȿ���
+### 标签长度控制
-���ڴ��Ͷ�������Ʊ�ǩ���ݣ�
+对于大型对象,建议控制标签内容:
```csharp
-// ���Ƽ�����¼���������
+// 不推荐:记录整个大对象
span.SetTag(largeObject);
-// �Ƽ���ֻ��¼�ؼ���Ϣ
+// 推荐:只记录关键信息
span.SetTag(new { Id = obj.Id, Name = obj.Name });
```
-### �������
+### 条件埋点
-���ڷǹؼ�·�������������Դ�����㣺
+对于非关键路径,可以条件性创建埋点:
```csharp
ISpan? span = null;
@@ -545,7 +545,7 @@ if (_tracer != null && IsImportantOperation())
try
{
- // ҵ����
+ // 业务逻辑
}
finally
{
@@ -555,87 +555,87 @@ finally
---
-## �쳣����
+## 异常处理
-### ApiException �����
+### ApiException 特殊处理
-ҵ���쳣 `ApiException` ���ᱻ���Ϊ����
+业务异常 `ApiException` 不会被标记为错误:
```csharp
catch (ApiException aex)
{
span?.SetError(aex, request);
- // ��¼Ϊ������㣬Tag�а���ҵ�������
+ // 记录为正常埋点,Tag中包含业务错误码
}
catch (Exception ex)
{
span?.SetError(ex, request);
- // ��¼Ϊ�쳣��㣬Error�а����쳣��Ϣ
+ // 记录为异常埋点,Error中包含异常消息
}
```
-### �쳣���
+### 异常埋点
-ÿ���쳣���Զ������������쳣��㣬���ڰ��쳣����ͳ�ƣ�
+每个异常会自动创建独立的异常埋点,便于按异常类型统计:
```csharp
-// ԭʼ���
+// 原始埋点
using var span = tracer.NewSpan("DatabaseQuery");
try
{
- // �׳��쳣
- throw new TimeoutException("��ѯ��ʱ");
+ // 抛出异常
+ throw new TimeoutException("查询超时");
}
catch (Exception ex)
{
span.SetError(ex, query);
- // �Զ����� "ex:TimeoutException" ���
+ // 自动创建 "ex:TimeoutException" 埋点
}
```
---
-## ��������
+## 常见问题
-### 1. ����������dz�ƽ̨��������
+### 1. 埋点数据在星尘平台看不到?
-������¼��㣺
-- ȷ����ע���dz���չ��`services.AddStardust()`
-- ����������ӵ��dz�������
-- ���Ӧ�����dz�ƽ̨�Ƿ���ע��
-- �鿴������־��ȷ�������������
+检查以下几点:
+- 确认已注入星尘扩展:`services.AddStardust()`
+- 检查网络连接到星尘服务器
+- 检查应用在星尘平台是否已注册
+- 查看本地日志,确认埋点正常创建
-### 2. ��������̫�٣�
+### 2. 采样数据太少?
-��������������
+调整采样参数:
```csharp
-tracer.MaxSamples = 10; // ��������������
-tracer.MaxErrors = 50; // �����쳣������
-tracer.Timeout = 1000; // ���ͳ�ʱ��ֵ
+tracer.MaxSamples = 10; // 增加正常采样数
+tracer.MaxErrors = 50; // 增加异常采样数
+tracer.Timeout = 1000; // 降低超时阈值
```
-### 3. ��ιر���㣿
+### 3. 如何关闭埋点?
```csharp
-// ��ʽ1����ע�� ITracer
-// services.AddStardust(); // ע�͵�
+// 方式1:不注入 ITracer
+// services.AddStardust(); // 注释掉
-// ��ʽ2��ʹ�ÿ�ʵ��
+// 方式2:使用空实现
DefaultTracer.Instance = null;
```
-### 4. ��β鿴����������ݣ�
+### 4. 如何查看本地埋点数据?
-DefaultTracer ���������־��
+DefaultTracer 会输出到日志:
```
Tracer[DataRetention] Total=10 Errors=0 Speed=0.02tps Cost=1500ms MaxCost=2000ms MinCost=1000ms
```
-### 5. ���������� Span ������
+### 5. 并发场景下 Span 会乱吗?
-���ᡣ`ISpan` ʹ�� `AsyncLocal<ISpan>` ���������ģ�ÿ���첽���̶�����
+不会。`ISpan` 使用 `AsyncLocal<ISpan>` 保存上下文,每个异步流程独立:
```csharp
public static AsyncLocal<ISpan?> Current { get; }
@@ -643,19 +643,19 @@ public static AsyncLocal<ISpan?> Current { get; }
---
-## �����
+## 参考资料
-- **�dz����ƽ̨**: https://newlifex.com/blood/stardust
+- **星尘监控平台**: https://newlifex.com/blood/stardust
- **W3C Trace Context**: https://www.w3.org/TR/trace-context/
-- **Դ��ֿ�**: https://github.com/NewLifeX/X
-- **�����ĵ�**: https://newlifex.com/core/tracer
+- **源码仓库**: https://github.com/NewLifeX/X
+- **在线文档**: https://newlifex.com/core/tracer
---
-## ������־
+## 更新日志
-- **2024-12-16**: �����ĵ����������ʵ����ʾ������
-- **2024-08**: ֧�� .NET 9.0
-- **2023-11**: ���� `Abandon()` ����
-- **2023-06**: �Ż�����أ���������
-- **2022**: ��ʼ�汾����
+- **2024-12-16**: 完善文档,补充最佳实践和示例代码
+- **2024-08**: 支持 .NET 9.0
+- **2023-11**: 增加 `Abandon()` 方法
+- **2023-06**: 优化对象池,提升性能
+- **2022**: 初始版本发布
diff --git "a/Doc/\351\233\252\350\212\261\347\256\227\346\263\225Snowflake.md" "b/Doc/\351\233\252\350\212\261\347\256\227\346\263\225Snowflake.md"
index ed77f2c..2e9118f 100644
--- "a/Doc/\351\233\252\350\212\261\347\256\227\346\263\225Snowflake.md"
+++ "b/Doc/\351\233\252\350\212\261\347\256\227\346\263\225Snowflake.md"
@@ -1,201 +1,201 @@
-# Snowflake ѩ���㷨ʹ���ֲ�
+# Snowflake 雪花算法使用手册
-���ĵ�����Դ�� `NewLife.Core/Data/Snowflake.cs` ����� `XUnitTest.Core/Data/SnowflakeTests.cs`������˵�� `Snowflake`��ѩ���㷨�ֲ�ʽ Id ������������ơ��÷���ע�����
+本文档基于源码 `NewLife.Core/Data/Snowflake.cs` 与测试 `XUnitTest.Core/Data/SnowflakeTests.cs`,用于说明 `Snowflake`(雪花算法分布式 Id 生成器)的设计、用法与注意事项。
-> �ؼ��ʣ�������WorkerId��ʱ��������кš�ʱ��ز�����Ⱥ���䣨Redis����
+> 关键词:单例、WorkerId、时间戳、序列号、时间回拨、集群分配(Redis)。
---
-## 1. ����
+## 1. 概述
-`Snowflake` ��һ�� 64 bit �� `Int64` ��Ϊȫ��Ψһ Id��
+`Snowflake` 用一个 64 bit 的 `Int64` 作为全局唯一 Id。
-λ���䣺
+位分配:
-- 1 bit�������������
-- 41 bit��ʱ��������룩
-- 10 bit�������ڵ㣨`WorkerId`��0~1023��
-- 12 bit�����кţ�0~4095��
+- 1 bit:保留(符号位)
+- 41 bit:时间戳(毫秒)
+- 10 bit:工作节点(`WorkerId`,0~1023)
+- 12 bit:序列号(0~4095)
-���ɵ� Id �߱������ص㣺
+生成的 Id 具备以下特点:
-- ����������������ʱ���ƽ���
-- ͬһ�����ڿ�������� 4096 �� Id
-- **��ͬһ�� `Snowflake` ʵ����**�ɱ�֤���ظ�
+- 大体趋势自增(按时间推进)
+- 同一毫秒内可生成最多 4096 个 Id
+- **在同一个 `Snowflake` 实例内**可保证不重复
-��ҪԼ����
+重要约束:
-- **ҵ���ڱ���ȷ������**���������������ڶ�� `Snowflake` ʵ�������� `WorkerId` ��ͬ������ܲ����ظ� Id��
+- **业务内必须确保单例**。若并发场景存在多个 `Snowflake` 实例,并且 `WorkerId` 相同,则可能产生重复 Id。
---
-## 2. ���ĸ���
+## 2. 核心概念
-### 2.1 `StartTimestamp`����ʼʱ�����
+### 2.1 `StartTimestamp`(起始时间戳)
-- ���ԣ�`public DateTime StartTimestamp { get; set; }`
-- Ĭ��ֵ��`UTC 1970-01-01` תΪ����ʱ�䣨`DateTimeKind.Local`��
+- 属性:`public DateTime StartTimestamp { get; set; }`
+- 默认值:`UTC 1970-01-01` 转为本地时间(`DateTimeKind.Local`)
-����Ҫ�㣺
+语义要点:
-- `Snowflake` ��Ѳ�������ʱ��ת���� `StartTimestamp` ����ʱ����Ȼ������õ���������
-- Ĭ��ʹ�ñ���ʱ�䣬��Ϊ�˷������ѩ�� Id ʱֱ�ӵõ�����ʱ�䣬������������ҵ�������ǰ��������ڷֱ�/�����ij�������
+- `Snowflake` 会把参与计算的时间转换到 `StartTimestamp` 所属时区,然后做差得到毫秒数。
+- 默认使用本地时间,是为了方便解析雪花 Id 时直接得到本地时间,并最大兼容已有业务(尤其是按本地日期分表/分区的场景)。
-ʹ�ý��飺
+使用建议:
-- `StartTimestamp` **�������״ε��� `NewId()` ǰ����**���״����ɺ����IJ���Ӱ���ѳ�ʼ��ʵ������Ϊ��ʼ������ֻ��һ�Σ���
+- `StartTimestamp` **必须在首次调用 `NewId()` 前设置**,首次生成后再修改不会影响已初始化实例(因为初始化过程只做一次)。
-### 2.2 `WorkerId`�������ڵ� Id��
+### 2.2 `WorkerId`(工作节点 Id)
-- ���ԣ�`public Int32 WorkerId { get; set; }`
-- ����0~1023��10 �
+- 属性:`public Int32 WorkerId { get; set; }`
+- 范围:0~1023(10 位)
-˵����
+说明:
-- �ڷֲ�ʽϵͳ�ڣ�`WorkerId` ��ȫ��Ψһ�Ծ����˿�ڵ��Ƿ������ظ� Id��
-- ������Ĭ���㷨��IP/����/�̣߳�**�����Ա�֤Ψһ**����Ҫ�������ⲿ��ʽ���䡣
+- 在分布式系统内,`WorkerId` 的全局唯一性决定了跨节点是否会产生重复 Id。
+- 仅依靠默认算法(IP/进程/线程)**无法绝对保证唯一**,高要求场景建议外部显式分配。
-### 2.3 `Sequence`�����кţ�
+### 2.3 `Sequence`(序列号)
-- ���ԣ�`public Int32 Sequence => _sequence;`
-- ����0~4095��12 �
+- 属性:`public Int32 Sequence => _sequence;`
+- 范围:0~4095(12 位)
-˵����
+说明:
-- ͬһ������ͨ���������кű�֤Ψһ��
-- ������������� 4095��ʱ���㷨�������ƽ�����һ����������ɡ�
+- 同一毫秒内通过递增序列号保证唯一。
+- 序列溢出(超过 4095)时,算法会逻辑上推进到下一毫秒继续生成。
---
-## 3. WorkerId ��ʼ�����ȼ�
+## 3. WorkerId 初始化优先级
-`Snowflake` ���״����� Id ʱ���Զ�ִ��һ�γ�ʼ����`Initialize()`���������ȼ����� `WorkerId`��
+`Snowflake` 在首次生成 Id 时会自动执行一次初始化(`Initialize()`),按优先级决定 `WorkerId`:
-1. ���ʵ�� `WorkerId > 0`��ʹ��ʵ��ֵ
-2. ������� `Snowflake.GlobalWorkerId > 0`��ʹ�� `GlobalWorkerId & 1023`
-3. ������� `Snowflake.Cluster != null`������ `JoinCluster(Cluster)` �Ӽ�Ⱥ����
-4. ����ʹ��Ĭ���㷨���ɣ����� IP ������ʵ���� + ����/�̣߳�
+1. 如果实例 `WorkerId > 0`:使用实例值
+2. 否则如果 `Snowflake.GlobalWorkerId > 0`:使用 `GlobalWorkerId & 1023`
+3. 否则如果 `Snowflake.Cluster != null`:调用 `JoinCluster(Cluster)` 从集群分配
+4. 否则:使用默认算法生成(基于 IP 派生的实例号 + 进程/线程)
-ע�⣺
+注意:
-- ������ʹ�õ����ж� `WorkerId <= 0`����� **`WorkerId=0` �ᱻ��Ϊ��δ���á��������ߺ�������**������ϣ���̶�Ϊ 0����Ҫ����ȷ����Ҫ������ʼ�����ǣ�һ�㲻���飩��
+- 代码中使用的是判断 `WorkerId <= 0`,因此 **`WorkerId=0` 会被视为“未设置”并继续走后续策略**。若你希望固定为 0,需要自行确保不要触发初始化覆盖(一般不建议)。
---
-## 4. API �ٲ�
+## 4. API 速查
### 4.1 `Int64 NewId()`
-���ڵ�ǰʱ��������һ�� Id��
+基于当前时间生成下一个 Id。
-��ΪҪ�㣺
+行为要点:
-- ʹ�� `DateTime.Now`������ʱ�䣩����ͨ�� `ConvertKind` ת���� `StartTimestamp` ��ʱ����
-- ����ʱ��ز���
- - ����ʱ��ز��һز����ȴ��� `MaxClockBack`��Լ 1 Сʱ + 10 �룩���׳� `InvalidOperationException`
- - ����ʹ����һ��ʱ����������ɣ����ֵ�ʵ��Ψһ�ԣ�
+- 使用 `DateTime.Now`(本地时间),并通过 `ConvertKind` 转换到 `StartTimestamp` 的时区。
+- 处理时间回拨:
+ - 若检测到时间回拨且回拨幅度大于 `MaxClockBack`(约 1 小时 + 10 秒),抛出 `InvalidOperationException`
+ - 否则使用上一次时间戳继续生成(保持单实例唯一性)
-������
+适用场景:
-- ����ҵ���������ɣ���ã���
+- 常规业务主键生成(最常用)。
### 4.2 `Int64 NewId(DateTime time)`
-����ָ��ʱ������ Id��Я����ǰʵ���� `WorkerId` �����кţ���
+基于指定时间生成 Id(携带当前实例的 `WorkerId` 与序列号)。
-ע�⣺
+注意:
-- ����Ϊͬһ����ָ������ʱ�䡱���ɳ��� 4096 �� Id��������ظ�����Ϊ���к�ֻ�� 12 λ����ȡģ����
+- 若你为同一个“指定毫秒时间”生成超过 4096 个 Id,则可能重复(因为序列号只有 12 位,会取模)。
-������
+适用场景:
-- ��Ҫ��ҵ��ʱ�乹����� Id�����簴�ɼ�ʱ����⣩��
+- 需要用业务时间构造插入 Id(例如按采集时间落库)。
### 4.3 `Int64 NewId(DateTime time, Int32 uid)`
-����ָ��ʱ������ Id��ʹ�� `uid` �ĵ� 10 λ��Ϊ `WorkerId`��1024 ���飩���Ա��� 12 λ���кš�
+基于指定时间生成 Id,使用 `uid` 的低 10 位作为 `WorkerId`(1024 分组),仍保留 12 位序列号。
-������
+适用场景:
-- ���������ݲɼ���ÿ 1024 ��������Ϊһ�飬ÿ��ÿ������������ 4096 �� Id��
+- 物联网数据采集:每 1024 个传感器为一组,每组每毫秒可生成最多 4096 个 Id。
-ע�⣺
+注意:
-- ��ͬһ����ͬһ�������ɳ��� 4096 �� Id��������ظ���
+- 若同一分组同一毫秒生成超过 4096 个 Id,则可能重复。
### 4.4 `Int64 NewId22(DateTime time, Int32 uid)`
-����ָ��ʱ������ Id��ʹ�� 22 λҵ�� Id��`uid & ((1<<22)-1)`�������ٱ������кš�
+基于指定时间生成 Id,使用 22 位业务 Id(`uid & ((1<<22)-1)`),不再保留序列号。
-������
+适用场景:
-- ���������ݲɼ���ÿ 4,194,304 ��������һ�飬ÿ��ÿ������� 1 �� Id��
-- ��������� upsert��ͬһ����ͬһ������д��������ʱֻ����һ�С�
+- 物联网数据采集:每 4,194,304 个传感器一组,每组每毫秒最多 1 个 Id。
+- 常用于配合 upsert:同一毫秒同一传感器写多行数据时只保留一行。
-ע�⣺
+注意:
-- ͬһҵ�� id ��ͬһ���������ɶ�� Id ���ظ�����Ϊû�����кţ���
+- 同一业务 id 在同一毫秒内生成多个 Id 会重复(因为没有序列号)。
### 4.5 `Int64 GetId(DateTime time)`
-��ʱ��ת��Ϊ��������ʱ�䲿�֡��� Id������ `WorkerId` �����кţ���
+把时间转换为“仅包含时间部分”的 Id(不带 `WorkerId` 与序列号)。
-������
+适用场景:
-- ����ʱ��Ƭ�β�ѯ����ʱ������ת��Ϊѩ�� Id ������з�Χ��ѯ��
+- 构造时间片段查询:将时间区间转换为雪花 Id 区间进行范围查询。
### 4.6 `Boolean TryParse(Int64 id, out DateTime time, out Int32 workerId, out Int32 sequence)`
-����ѩ�� Id���õ�ʱ�䡢`WorkerId`�����кš�
+解析雪花 Id,得到时间、`WorkerId`、序列号。
-˵����
+说明:
-- �����õ��� `time` �� `StartTimestamp` ����ʱ����ʱ�䡣
+- 解析得到的 `time` 是 `StartTimestamp` 所属时区的时间。
### 4.7 `DateTime ConvertKind(DateTime time)`
-������ʱ��ת��Ϊ�� `StartTimestamp` ��ͬ��ʱ�������������
+把输入时间转换为与 `StartTimestamp` 相同的时区,便于相减。
-����
+规则:
-- `time.Kind == DateTimeKind.Unspecified`��ֱ�ӷ��أ�����ת����
-- `StartTimestamp.Kind == Utc`������ `time.ToUniversalTime()`
-- `StartTimestamp.Kind == Local`������ `time.ToLocalTime()`
+- `time.Kind == DateTimeKind.Unspecified`:直接返回(不做转换)
+- `StartTimestamp.Kind == Utc`:返回 `time.ToUniversalTime()`
+- `StartTimestamp.Kind == Local`:返回 `time.ToLocalTime()`
---
-## 5. ��Ⱥģʽ��ȷ�� WorkerId ����Ψһ
+## 5. 集群模式:确保 WorkerId 绝对唯一
### 5.1 `static ICache? Cluster`
-`Snowflake.Cluster` ��������һ������ʵ����Ϊ WorkerId ������������ʹ�� Redis��
+`Snowflake.Cluster` 用于配置一个缓存实例作为 WorkerId 分配器,建议使用 Redis。
-- �� `Cluster != null` ��ʵ�� `WorkerId` δ��ʽ����ʱ����ʼ���λ���� `JoinCluster(Cluster)`��
+- 当 `Cluster != null` 且实例 `WorkerId` 未显式设置时,初始化阶段会调用 `JoinCluster(Cluster)`。
### 5.2 `void JoinCluster(ICache cache, String key = "SnowflakeWorkerId")`
-ͨ���������Ӽ�Ⱥ��ȡ WorkerId��
+通过自增键从集群获取 WorkerId:
- `workerId = (Int32)cache.Increment(key, 1)`
- `WorkerId = workerId & 1023`
-ʹ�ý��飺
+使用建议:
-- �ڶ����/��ڵ㳡�����������Ȳ��ü�Ⱥ���� WorkerId��
-- ��Ҫ���ֻ�����dev/test/prod��ʱ������Ϊ��ͬ����ʹ�ò�ͬ�� `key`������ WorkerId ���佻�档
+- 在多进程/多节点场景,无脑优先采用集群分配 WorkerId。
+- 需要区分环境(dev/test/prod)时,建议为不同环境使用不同的 `key`,避免 WorkerId 分配交叉。
---
-## 6. ��ȷʹ������
+## 6. 正确使用姿势
-### 6.1 ��Ӧ���ڱ��ֵ���
+### 6.1 在应用内保持单例
-�ؼ��㣺
+关键点:
-- ÿ��Ӧ��/�����ڣ�����ֻ����һ��ȫ�� `Snowflake` ʵ����
-- ��ʹ�� ORM/�м�������� XCode������ȷ��ͬһ�ű�����ͬһҵ����Ҫ���� new һ�� `Snowflake`��
+- 每个应用/服务内,尽量只创建一个全局 `Snowflake` 实例。
+- 若使用 ORM/中间件(例如 XCode),需确保同一张表(或同一业务域)不要各自 new 一个 `Snowflake`。
-ʾ����
+示例:
```csharp
using NewLife.Data;
@@ -204,7 +204,7 @@ public static class IdGenerator
{
public static readonly Snowflake Instance = new()
{
- // ������Ҫ�����״ε��� NewId ǰ����
+ // 如有需要,在首次调用 NewId 前设置
// StartTimestamp = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local),
// WorkerId = 1,
};
@@ -213,20 +213,20 @@ public static class IdGenerator
var id = IdGenerator.Instance.NewId();
```
-### 6.2 ��ʽָ�� WorkerId���Ƽ���
+### 6.2 显式指定 WorkerId(推荐)
```csharp
var snow = new Snowflake { WorkerId = 1 };
var id = snow.NewId();
```
-### 6.3 ʹ�ü�Ⱥ���� WorkerId���Ƽ����ֲ�ʽ������
+### 6.3 使用集群分配 WorkerId(推荐,分布式场景)
```csharp
using NewLife.Caching;
using NewLife.Data;
-Snowflake.Cluster = /* RedisCache ʵ�� */;
+Snowflake.Cluster = /* RedisCache 实例 */;
var snow = new Snowflake();
var id = snow.NewId();
@@ -234,44 +234,44 @@ var id = snow.NewId();
---
-## 7. �����������
+## 7. 常见问题与坑
-### 7.1 Ϊʲôǿ������������
+### 7.1 为什么强调“单例”?
-`Snowflake` ֻ��֤����ʵ�������ɵ� Id Ψһ��
+`Snowflake` 只保证“本实例”生成的 Id 唯一。
-- ֻҪ���ֶ��ʵ�������� `WorkerId` һ���������¾Ϳ��ܲ����ظ���
+- 只要出现多个实例,并且 `WorkerId` 一样,并发下就可能产生重复。
-### 7.2 Ĭ�� WorkerId �Ƿ�ɿ���
+### 7.2 默认 WorkerId 是否可靠?
-Ĭ�ϲ���ʹ�� IP ����ʵ�� Id + ����/�߳���Ϣ��Ŀ���ǽ���ͬ����ͻ���ʣ����������л����¾���Ψһ��
+默认策略使用 IP 派生实例 Id + 进程/线程信息,目的是降低同机冲突概率,但无法在所有环境下绝对唯一。
-- ����������NAT��ͬһ������ IP �仯�����������ȶ����������ͻ��
-- ��Ҫ��ǿ�ҽ��飺��ʽ WorkerId ��ʹ�� Redis �������䡣
+- 容器环境、NAT、同一局域网 IP 变化、进程重启等都可能引入冲突。
+- 高要求场景强烈建议:显式 WorkerId 或使用 Redis 自增分配。
-### 7.3 ʱ��ز��ᷢ��ʲô��
+### 7.3 时间回拨会发生什么?
-- С��Χ�ز����������ϴ�ʱ����������ɣ����ֵ�ʵ�����ظ���
-- �ز������׳��쳣�ܾ����ɣ���ֹ�������ײ����
+- 小范围回拨:会沿用上次时间戳继续生成,保持单实例不重复。
+- 回拨过大:抛出异常拒绝生成(防止大概率碰撞)。
-### 7.4 ʹ�� `NewId(DateTime time)` �Ƿ�һ��Ψһ��
+### 7.4 使用 `NewId(DateTime time)` 是否一定唯一?
-��һ����
+不一定。
-- ��ͬһ�����ڣ����к�ֻ�� 12 λ��4096����������ȡģ�����ظ����ա�
-- ���� API ���ʺϡ���ʱ�����/��������ҵ���������Ǹ߲���д��ͬһ��ҵ��ʱ��㡣
+- 在同一毫秒内,序列号只有 12 位(4096),超出会取模导致重复风险。
+- 这类 API 更适合“按时间落库/分区”的业务需求,而不是高并发写入同一个业务时间点。
---
-## 8. ������˵��
+## 8. 兼容性说明
-- `Snowflake` ���ڻ����⣬���� `net45` ~ `net10` ��Ŀ���ܡ�
-- �㷨���Ļ��� `DateTime`��`Interlocked`��`Volatile`��`ICache` ��ͨ�� API��
+- `Snowflake` 属于基础库,面向 `net45` ~ `net10` 多目标框架。
+- 算法核心基于 `DateTime`、`Interlocked`、`Volatile`、`ICache` 等通用 API。
---
-## 9. �������
+## 9. 相关链接
-- �����ĵ���`https://newlifex.com/core/snow_flake`
-- Դ�룺`NewLife.Core/Data/Snowflake.cs`
-- ��Ԫ���ԣ�`XUnitTest.Core/Data/SnowflakeTests.cs`
+- 在线文档:`https://newlifex.com/core/snow_flake`
+- 源码:`NewLife.Core/Data/Snowflake.cs`
+- 单元测试:`XUnitTest.Core/Data/SnowflakeTests.cs`
diff --git "a/Doc/\351\253\230\347\272\247\345\256\232\346\227\266\345\231\250TimerX.md" "b/Doc/\351\253\230\347\272\247\345\256\232\346\227\266\345\231\250TimerX.md"
index b921b18..5795942 100644
--- "a/Doc/\351\253\230\347\272\247\345\256\232\346\227\266\345\231\250TimerX.md"
+++ "b/Doc/\351\253\230\347\272\247\345\256\232\346\227\266\345\231\250TimerX.md"
@@ -1,203 +1,203 @@
-# ����ʱ��TimerX
+# 高级定时器TimerX
-## ����
+## 概述
-`NewLife.Threading.TimerX` ��һ������ǿ��Ķ�ʱ��ʵ�֣����ϵͳ `System.Threading.Timer` �����������ƣ�
+`NewLife.Threading.TimerX` 是一个功能强大的定时器实现,相比系统 `System.Threading.Timer` 具有以下优势:
-- **��������**���ص�ִ����Ϻ�ſ�ʼ��ʱ��һ��
-- **֧���첽�ص�**��ԭ��֧�� `async/await`
-- **����ʱ��ִ��**��֧�̶ֹ�ʱ��ִ�У���ÿ��2�㣩
-- **Cron ����ʽ**��֧�ָ��ӵĶ�ʱ����
-- **��·��**������ `ITracer` ���֧��
-- **��ȫ�ͷ�**�������ھ�̬�������ϣ����ⱻGC��ǰ����
+- **不可重入**:回调执行完毕后才开始计时下一次
+- **支持异步回调**:原生支持 `async/await`
+- **绝对时间执行**:支持固定时刻执行(如每天2点)
+- **Cron 表达式**:支持复杂的定时规则
+- **链路追踪**:内置 `ITracer` 埋点支持
+- **安全释放**:挂载在静态调度器上,避免被GC提前回收
-**�����ռ�**: `NewLife.Threading`
-**Դ��**: [NewLife.Core/Threading/TimerX.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/TimerX.cs)
+**命名空间**: `NewLife.Threading`
+**源码**: [NewLife.Core/Threading/TimerX.cs](https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/TimerX.cs)
---
-## ��������
+## 快速入门
-### �����÷���������ִ��
+### 基础用法:周期性执行
```csharp
using NewLife.Threading;
-// 1����״�ִ�У�Ȼ��ÿ5��ִ��һ��
+// 1秒后首次执行,然后每5秒执行一次
var timer = new TimerX(state =>
{
- Console.WriteLine($"ִ��ʱ�䣺{DateTime.Now}");
+ Console.WriteLine($"执行时间:{DateTime.Now}");
}, null, 1000, 5000);
-// ʹ����ϼǵ��ͷ�
+// 使用完毕记得释放
timer.Dispose();
```
-**����˵��**��
-- `state`���û����ݣ��ᴫ�ݸ��ص�����
-- `dueTime`���ӳ�ʱ�䣨���룩���״�ִ��ǰ�ȴ���ʱ��
-- `period`��������ڣ����룩����Ϊ0��-1��ʾִֻ��һ��
+**参数说明**:
+- `state`:用户数据,会传递给回调函数
+- `dueTime`:延迟时间(毫秒),首次执行前等待的时间
+- `period`:间隔周期(毫秒),设为0或-1表示只执行一次
-### �첽�ص�
+### 异步回调
```csharp
-// ֧�� async/await ���첽�ص�
+// 支持 async/await 的异步回调
var timer = new TimerX(async state =>
{
- await Task.Delay(100); // ģ���첽����
- Console.WriteLine("�첽�������");
+ await Task.Delay(100); // 模拟异步操作
+ Console.WriteLine("异步任务完成");
}, null, 1000, 5000);
```
-**�Զ�����**��
-- ʹ�� `Func<Object, Task>` ʱ���Զ����� `IsAsyncTask = true` �� `Async = true`
+**自动设置**:
+- 使用 `Func<Object, Task>` 时,自动设置 `IsAsyncTask = true` 和 `Async = true`
-### ����ʱ��ִ��
+### 绝对时间执行
```csharp
-// ÿ���賿2��ִ��
+// 每天凌晨2点执行
var start = DateTime.Today.AddHours(2);
var timer = new TimerX(state =>
{
- Console.WriteLine("ִ��������������");
-}, null, start, 24 * 3600 * 1000); // ����24Сʱ
+ Console.WriteLine("执行数据清理任务");
+}, null, start, 24 * 3600 * 1000); // 周期24小时
```
-**�ص�**��
-- ��� `startTime` С�ڵ�ǰʱ�䣬���Զ��� `period` ֱ�����ڵ�ǰʱ��
-- �Զ����� `Absolutely = true`
-- ���� `SetNext` Ӱ�죬ʼ���ڹ̶�ʱ��ִ��
+**特点**:
+- 如果 `startTime` 小于当前时间,会自动加 `period` 直到大于当前时间
+- 自动设置 `Absolutely = true`
+- 不受 `SetNext` 影响,始终在固定时刻执行
-### Cron ����ʽ
+### Cron 表达式
```csharp
-// ÿ������������9��ִ��
+// 每个工作日早上9点执行
var timer = new TimerX(state =>
{
- Console.WriteLine("����������");
+ Console.WriteLine("工作日任务");
}, null, "0 0 9 * * 1-5");
-// ֧�ֶ��Cron����ʽ���ֺŷָ�
+// 支持多个Cron表达式,分号分隔
var timer2 = new TimerX(state =>
{
- Console.WriteLine("�������");
-}, null, "0 0 2 * * 1-5;0 0 3 * * 6"); // ������2�㣬����3��
+ Console.WriteLine("混合任务");
+}, null, "0 0 2 * * 1-5;0 0 3 * * 6"); // 工作日2点,周六3点
```
-**�Զ�����**��
-- ʹ�� Cron ����ʽʱ���Զ����� `Absolutely = true`
-- ��һ��ִ��ʱ���� Cron ����
+**自动设置**:
+- 使用 Cron 表达式时,自动设置 `Absolutely = true`
+- 下一次执行时间由 Cron 计算
---
-## ��������
+## 核心特性
-### 1. �����������
+### 1. 不可重入机制
-ϵͳ `Timer` �����⣺
+系统 `Timer` 的问题:
```csharp
-// System.Threading.Timer ������
+// System.Threading.Timer 的问题
var timer = new Timer(_ =>
{
- Thread.Sleep(3000); // ���������ʱ3��
- Console.WriteLine("ִ��");
-}, null, 0, 1000); // ÿ1�봥��
+ Thread.Sleep(3000); // 假设任务耗时3秒
+ Console.WriteLine("执行");
+}, null, 0, 1000); // 每1秒触发
-// ���������ͬʱ�ж���ص���ִ�У���ɲ������⣡
+// 结果:可能同时有多个回调在执行,造成并发问题!
```
-TimerX �Ľ��������
+TimerX 的解决方案:
```csharp
var timer = new TimerX(_ =>
{
- Thread.Sleep(3000); // ��ʱ3��
- Console.WriteLine("ִ��");
+ Thread.Sleep(3000); // 耗时3秒
+ Console.WriteLine("执行");
}, null, 0, 1000);
-// ִ�����̣�
-// 0�룺��ʼ��1��ִ��
-// 3�룺��1��ִ����ϣ��ȴ�1��
-// 4�룺��ʼ��2��ִ��
-// 7�룺��2��ִ����ϣ��ȴ�1��
-// 8�룺��ʼ��3��ִ��
+// 执行流程:
+// 0秒:开始第1次执行
+// 3秒:第1次执行完毕,等待1秒
+// 4秒:开始第2次执行
+// 7秒:第2次执行完毕,等待1秒
+// 8秒:开始第3次执行
// ...
```
-**ԭ��**���ص�ִ����Ϻ�ſ�ʼ������һ�ε��ӳ�ʱ�䣬ȷ��ͬһʱ��ֻ��һ���ص���ִ�С�
+**原理**:回调执行完毕后才开始计算下一次的延迟时间,确保同一时刻只有一个回调在执行。
-### 2. ���� TickCount �ľ���ʱ
+### 2. 基于 TickCount 的精准计时
-TimerX ʹ�� `Runtime.TickCount64` ��Ϊ��ʱ������ϵͳʱ��ز���
+TimerX 使用 `Runtime.TickCount64` 作为计时基准,无惧系统时间回拨:
```csharp
-// ��ʹ�ֶ�����ϵͳʱ�䣬TimerX Ҳ����Ӱ��
+// 即使手动调整系统时间,TimerX 也不受影响
var timer = new TimerX(_ =>
{
- Console.WriteLine($"ִ�У�{DateTime.Now}");
+ Console.WriteLine($"执行:{DateTime.Now}");
}, null, 0, 5000);
```
-**����**��
-- ʹ�ÿ������������ϵͳʱ��
-- ��������ʱ��ʱ������Ӱ��
-- ÿ�� `SetNextTick` ��ˢ��ʱ������Զ�����Ư��
+**优势**:
+- 使用开机嘀嗒数而非系统时钟
+- 不受夏令时、时区调整影响
+- 每次 `SetNextTick` 会刷新时间基准,自动修正漂移
-### 3. ����ʱ���� Cron
+### 3. 绝对时间与 Cron
-- **`Absolutely = true`**����ʾ����ʱ��ִ�У����� `SetNext` Ӱ��
-- **Cron ���캯��**���Զ����� `Absolutely = true`��ͨ�� `Cron.GetNext(now)` ������һ��ִ��ʱ��
+- **`Absolutely = true`**:表示绝对时间执行,不受 `SetNext` 影响
+- **Cron 构造函数**:自动设置 `Absolutely = true`,通过 `Cron.GetNext(now)` 计算下一次执行时间
```csharp
-// ����ʱ�䶨ʱ��
+// 绝对时间定时器
var timer = new TimerX(_ => { }, null, DateTime.Today.AddHours(2), 24 * 3600 * 1000);
timer.Absolutely; // true
-// Cron ��ʱ��
+// Cron 定时器
var timer2 = new TimerX(_ => { }, null, "0 0 2 * * *");
timer2.Absolutely; // true
-timer2.Crons; // Cron����
+timer2.Crons; // Cron数组
```
---
-## ���캯�����
+## 构造函数详解
-### 1. ��ͨ���ڶ�ʱ����ͬ����
+### 1. 普通周期定时器(同步)
```csharp
public TimerX(TimerCallback callback, Object? state, Int32 dueTime, Int32 period, String? scheduler = null)
```
-**����**��
-- `callback`: �ص�ί�� `void Callback(Object state)`
-- `state`: �û�����
-- `dueTime`: �ӳ�ʱ�䣨���룩���״�ִ��ǰ�ȴ�
-- `period`: ������ڣ����룩��0��-1��ʾִֻ��һ��
-- `scheduler`: ���������ƣ�Ĭ��ʹ�� `TimerScheduler.Default`
+**参数**:
+- `callback`: 回调委托 `void Callback(Object state)`
+- `state`: 用户数据
+- `dueTime`: 延迟时间(毫秒),首次执行前等待
+- `period`: 间隔周期(毫秒),0或-1表示只执行一次
+- `scheduler`: 调度器名称,默认使用 `TimerScheduler.Default`
-**ʾ��**��
+**示例**:
```csharp
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ��");
+ Console.WriteLine("执行");
}, null, 1000, 5000);
```
-### 2. �첽���ڶ�ʱ��
+### 2. 异步周期定时器
```csharp
public TimerX(Func<Object, Task> callback, Object? state, Int32 dueTime, Int32 period, String? scheduler = null)
```
-**����**��
-- `callback`: �첽�ص�ί�� `async Task Callback(Object state)`
-- ��������ͬ��
+**参数**:
+- `callback`: 异步回调委托 `async Task Callback(Object state)`
+- 其他参数同上
-**�Զ�����**��
+**自动设置**:
- `IsAsyncTask = true`
- `Async = true`
-**ʾ��**��
+**示例**:
```csharp
var timer = new TimerX(async _ =>
{
@@ -205,313 +205,313 @@ var timer = new TimerX(async _ =>
}, null, 1000, 5000);
```
-### 3. ����ʱ�䶨ʱ����ͬ����
+### 3. 绝对时间定时器(同步)
```csharp
public TimerX(TimerCallback callback, Object? state, DateTime startTime, Int32 period, String? scheduler = null)
```
-**����**��
-- `startTime`: ���Կ�ʼʱ�䣬ָ��ʱ��ִ��
-- `period`: ������ڣ����룩���������0
+**参数**:
+- `startTime`: 绝对开始时间,指定时刻执行
+- `period`: 间隔周期(毫秒),必须大于0
-**�Զ�����**��
+**自动设置**:
- `Absolutely = true`
-- ��� `startTime` С�ڵ�ǰʱ�䣬�Զ��� `period` ����
+- 如果 `startTime` 小于当前时间,自动加 `period` 对齐
-**ʾ��**��
+**示例**:
```csharp
-// ÿ���賿2��ִ��
+// 每天凌晨2点执行
var start = DateTime.Today.AddHours(2);
var timer = new TimerX(_ =>
{
- Console.WriteLine("�賿����");
+ Console.WriteLine("凌晨任务");
}, null, start, 24 * 3600 * 1000);
```
-### 4. ����ʱ�䶨ʱ�����첽��
+### 4. 绝对时间定时器(异步)
```csharp
public TimerX(Func<Object, Task> callback, Object? state, DateTime startTime, Int32 period, String? scheduler = null)
```
-**�Զ�����**��
+**自动设置**:
- `IsAsyncTask = true`
- `Async = true`
- `Absolutely = true`
-### 5. Cron ��ʱ����ͬ����
+### 5. Cron 定时器(同步)
```csharp
public TimerX(TimerCallback callback, Object? state, String cronExpression, String? scheduler = null)
```
-**����**��
-- `cronExpression`: Cron ����ʽ��֧�ַֺŷָ��������ʽ
+**参数**:
+- `cronExpression`: Cron 表达式,支持分号分隔多个表达式
-**�Զ�����**��
+**自动设置**:
- `Absolutely = true`
-- ��������ʽ�����浽 `_crons` ����
+- 解析表达式并保存到 `_crons` 数组
-**ʾ��**��
+**示例**:
```csharp
-// ÿ������������9��
+// 每个工作日早上9点
var timer = new TimerX(_ =>
{
- Console.WriteLine("����������");
+ Console.WriteLine("工作日任务");
}, null, "0 0 9 * * 1-5");
-// ���ʱ���
+// 多个时间点
var timer2 = new TimerX(_ =>
{
- Console.WriteLine("�������");
+ Console.WriteLine("混合任务");
}, null, "0 0 2 * * 1-5;0 0 3 * * 6");
```
-### 6. Cron ��ʱ�����첽��
+### 6. Cron 定时器(异步)
```csharp
public TimerX(Func<Object, Task> callback, Object? state, String cronExpression, String? scheduler = null)
```
-**�Զ�����**��
+**自动设置**:
- `IsAsyncTask = true`
- `Async = true`
- `Absolutely = true`
---
-## ��������
+## 核心属性
-| ���� | ���� | ˵�� |
+| 属性 | 类型 | 说明 |
|-----|------|------|
-| `Id` | Int32 | ��ʱ��Ψһ��ʶ���Զ����� |
-| `Period` | Int32 | ������ڣ����룩��0��-1��ʾִֻ��һ�� |
-| `Async` | Boolean | �Ƿ��첽ִ�У�Ĭ�� false |
-| `Absolutely` | Boolean | �Ƿ���Ծ�ȷʱ��ִ�У�Ĭ�� false |
-| `Calling` | Boolean | �ص��Ƿ�����ִ�У�ֻ���� |
-| `Timers` | Int32 | �ۼƵ��ô�����ֻ���� |
-| `Cost` | Int32 | ƽ����ʱ�����룬ֻ���� |
-| `NextTime` | DateTime | ��һ�ε���ʱ�䣨ֻ���� |
-| `NextTick` | Int64 | ��һ��ִ��ʱ����������ֻ���� |
-| `Crons` | Cron[] | Cron ����ʽ���ϣ�ֻ���� |
-| `Tracer` | ITracer | ��·���� |
-| `TracerName` | String | ��·�����ƣ�Ĭ�� `timer:{������}` |
-| `State` | Object | �û����ݣ������ô洢 |
-| `Scheduler` | TimerScheduler | ���������� |
+| `Id` | Int32 | 定时器唯一标识,自动分配 |
+| `Period` | Int32 | 间隔周期(毫秒),0或-1表示只执行一次 |
+| `Async` | Boolean | 是否异步执行,默认 false |
+| `Absolutely` | Boolean | 是否绝对精确时间执行,默认 false |
+| `Calling` | Boolean | 回调是否正在执行(只读) |
+| `Timers` | Int32 | 累计调用次数(只读) |
+| `Cost` | Int32 | 平均耗时(毫秒,只读) |
+| `NextTime` | DateTime | 下一次调用时间(只读) |
+| `NextTick` | Int64 | 下一次执行时间的嘀嗒数(只读) |
+| `Crons` | Cron[] | Cron 表达式集合(只读) |
+| `Tracer` | ITracer | 链路追踪器 |
+| `TracerName` | String | 链路追踪名称,默认 `timer:{方法名}` |
+| `State` | Object | 用户数据,弱引用存储 |
+| `Scheduler` | TimerScheduler | 所属调度器 |
---
-## �����
+## 核心方法
-### SetNext - ������һ��ִ��ʱ��
+### SetNext - 设置下一次执行时间
```csharp
-/// <summary>������һ������ʱ��</summary>
-/// <param name="ms">�ӳٺ�������С�ڵ���0��ʾ���ϵ���</param>
+/// <summary>设置下一次运行时间</summary>
+/// <param name="ms">延迟毫秒数。小于等于0表示马上调度</param>
public void SetNext(Int32 ms)
```
-**ʾ��**��
+**示例**:
```csharp
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ��");
+ Console.WriteLine("执行");
- // ��̬������һ��ִ��ʱ��
+ // 动态调整下一次执行时间
if (someCondition)
- timer.SetNext(10000); // 10���ִ��
+ timer.SetNext(10000); // 10秒后执行
else
- timer.SetNext(1000); // 1���ִ��
+ timer.SetNext(1000); // 1秒后执行
}, null, 1000, 5000);
```
-**ע��**��
-- ���� `Absolutely = true` �Ķ�ʱ��������ʱ�䡢Cron����`SetNext` ��Ч
-- ���ú�ỽ�ѵ������������
+**注意**:
+- 对于 `Absolutely = true` 的定时器(绝对时间、Cron),`SetNext` 无效
+- 调用后会唤醒调度器立即检查
-### Change - ���ļ�ʱ������
+### Change - 更改计时器参数
```csharp
-/// <summary>���ļ�ʱ��������ʱ��ͷ�������֮���ʱ����</summary>
-/// <param name="dueTime">�ӳ�ʱ��</param>
-/// <param name="period">�������</param>
-/// <returns>�Ƿ�ɹ�����</returns>
+/// <summary>更改计时器的启动时间和方法调用之间的时间间隔</summary>
+/// <param name="dueTime">延迟时间</param>
+/// <param name="period">间隔周期</param>
+/// <returns>是否成功更改</returns>
public Boolean Change(TimeSpan dueTime, TimeSpan period)
```
-**ʾ��**��
+**示例**:
```csharp
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ��");
+ Console.WriteLine("执行");
}, null, 1000, 5000);
-// ��Ϊ2����״�ִ�У�Ȼ��ÿ10��һ��
+// 修改为2秒后首次执行,然后每10秒一次
timer.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10));
```
-**����**��
-- ���� `Absolutely = true` �Ķ�ʱ�������� false����ʧ��
-- ���� Cron ��ʱ�������� false����ʧ��
-- `period` Ϊ������ Infinite ʱ����ʱ���ᱻ����
+**限制**:
+- 对于 `Absolutely = true` 的定时器,返回 false,修改失败
+- 对于 Cron 定时器,返回 false,修改失败
+- `period` 为负数或 Infinite 时,定时器会被销毁
-### Dispose - ���ٶ�ʱ��
+### Dispose - 销毁定时器
```csharp
-/// <summary>���ٶ�ʱ��</summary>
+/// <summary>销毁定时器</summary>
public void Dispose()
```
-**ʾ��**��
+**示例**:
```csharp
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ��");
+ Console.WriteLine("执行");
}, null, 1000, 5000);
-// ʹ������ͷ�
+// 使用完毕释放
timer.Dispose();
```
-**��Ҫ��**��
-- TimerX �����ھ�̬������ `TimerScheduler` ��
-- **�����ֶ����� `Dispose()`** ���ܴӵ������Ƴ�
-- ���������ڴ�й©�Ͷ�ʱ������ִ��
+**重要性**:
+- TimerX 挂载在静态调度器 `TimerScheduler` 上
+- **必须手动调用 `Dispose()`** 才能从调度器移除
+- 否则会造成内存泄漏和定时器继续执行
---
-## ��̬����
+## 静态方法
-### Delay - �ӳ�ִ��
+### Delay - 延迟执行
```csharp
-/// <summary>�ӳ�ִ��һ��ί��</summary>
-/// <param name="callback">�ص�ί��</param>
-/// <param name="ms">�ӳٺ�����</param>
-/// <returns>��ʱ��ʵ��</returns>
+/// <summary>延迟执行一个委托</summary>
+/// <param name="callback">回调委托</param>
+/// <param name="ms">延迟毫秒数</param>
+/// <returns>定时器实例</returns>
public static TimerX Delay(TimerCallback callback, Int32 ms)
```
-**ʾ��**��
+**示例**:
```csharp
-// 10���ִ��һ�Σ�Ȼ������
+// 10秒后执行一次,然后销毁
var timer = TimerX.Delay(_ =>
{
- Console.WriteLine("�ӳ�����ִ��");
+ Console.WriteLine("延迟任务执行");
}, 10000);
-// ע�⣺ί�п��ܻ�ûִ�У�timer����ͱ�GC������
-// ���鱣��timer����
+// 注意:委托可能还没执行,timer对象就被GC回收了
+// 建议保持timer引用
```
-**ע��**��
-- �Զ����� `Async = true`
-- ��ִ��һ�Σ�Period=0��
-- **����**����������� `timer` ���ã����ܱ� GC ���յ���δִ��
+**注意**:
+- 自动设置 `Async = true`
+- 仅执行一次(Period=0)
+- **警告**:如果不保持 `timer` 引用,可能被 GC 回收导致未执行
-### Now - ����ĵ�ǰʱ��
+### Now - 缓存的当前时间
```csharp
-/// <summary>��ǰʱ�䡣��ʱ��ȡϵͳʱ�䣬����Ƶ����ȡ�������ƿ��</summary>
+/// <summary>当前时间。定时读取系统时间,避免频繁读取造成性能瓶颈</summary>
public static DateTime Now { get; }
```
-**ʾ��**��
+**示例**:
```csharp
-var now = TimerX.Now; // �������� DateTime.Now
+var now = TimerX.Now; // 性能优于 DateTime.Now
Console.WriteLine(now);
```
-**ԭ��**��
-- ÿ500�������һ��ϵͳʱ��
-- ����Ƶ������ `DateTime.Now` �������ƿ��
-- �����ڶ�ʱ�侫��Ҫ�ߵij�������500ms��
+**原理**:
+- 每500毫秒更新一次系统时间
+- 避免频繁调用 `DateTime.Now` 造成性能瓶颈
+- 适用于对时间精度要求不高的场景(±500ms)
---
-## ������ TimerScheduler
+## 调度器 TimerScheduler
-TimerX ���� `TimerScheduler` ����ͳһ���ȡ�
+TimerX 依赖 `TimerScheduler` 进行统一调度。
-### Ĭ�ϵ�����
+### 默认调度器
```csharp
var timer = new TimerX(_ => { }, null, 1000, 5000);
timer.Scheduler; // TimerScheduler.Default
```
-### �Զ��������
+### 自定义调度器
```csharp
-// ����ר��������
+// 创建专属调度器
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ��");
+ Console.WriteLine("执行");
}, null, 1000, 5000, "MyScheduler");
timer.Scheduler.Name; // "MyScheduler"
```
-**����**��
-- ��Ҫ�����ĵ����̳߳�
-- ���벻ͬҵ��Ķ�ʱ��
-- ���Ʋ�ͬ�����������ȼ�
+**适用场景**:
+- 需要独立的调度线程池
+- 隔离不同业务的定时器
+- 控制不同调度器的优先级
---
-## ��·��
+## 链路追踪
-TimerX ������·��֧�֣��Զ�Ϊÿ��ִ�д��� Span��
+TimerX 内置链路追踪支持,自动为每次执行创建 Span。
-### ��������
+### 设置追踪器
```csharp
using NewLife.Log;
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ��");
+ Console.WriteLine("执行");
}, null, 1000, 5000)
{
- Tracer = DefaultTracer.Instance, // ��������
- TracerName = "MyTask" // �Զ����������
+ Tracer = DefaultTracer.Instance, // 设置追踪器
+ TracerName = "MyTask" // 自定义埋点名称
};
```
-### ������
+### 追踪数据
-ÿ�ζ�ʱ���������ᴴ��һ�� Span��
-- **����**��Ĭ��Ϊ `timer:{������}`����ͨ�� `TracerName` �Զ���
-- **��ǩ**����¼��ʱ��ID�����ڵ���Ϣ
-- **��ʱ**����¼ÿ�λص�ִ�е�ʱ��
+每次定时器触发,会创建一个 Span:
+- **名称**:默认为 `timer:{方法名}`,可通过 `TracerName` 自定义
+- **标签**:记录定时器ID、周期等信息
+- **耗时**:记录每次回调执行的时间
-**�鿴ͳ��**��
+**查看统计**:
```
Tracer[timer:DoWork] Total=100 Errors=0 Speed=0.02tps Cost=150ms MaxCost=200ms MinCost=100ms
```
-�����[��·��ITracer](tracer-��·��ITracer.md)
+详见:[链路追踪ITracer](tracer-链路追踪ITracer.md)
---
-## ʹ�ó���
+## 使用场景
-### 1. ������������
+### 1. 定期数据清理
```csharp
-// ÿ���賿3��������������
+// 每天凌晨3点清理过期数据
var timer = new TimerX(state =>
{
var days = (Int32)state!;
var before = DateTime.Now.AddDays(-days);
var count = Database.Delete("WHERE CreateTime < @time", new { time = before });
- Console.WriteLine($"������ {count} ����������");
+ Console.WriteLine($"清理了 {count} 条过期数据");
}, 30, DateTime.Today.AddHours(3), 24 * 3600 * 1000);
```
-### 2. �������
+### 2. 心跳检测
```csharp
var timer = new TimerX(_ =>
@@ -520,37 +520,37 @@ var timer = new TimerX(_ =>
{
if (client.LastActive.AddMinutes(5) < DateTime.Now)
{
- Console.WriteLine($"�ͻ��� {client.Id} ��ʱ���Ͽ�����");
+ Console.WriteLine($"客户端 {client.Id} 超时,断开连接");
client.Disconnect();
}
}
-}, null, 0, 60000); // ÿ���Ӽ��һ��
+}, null, 0, 60000); // 每分钟检查一次
```
-### 3. ��������ͬ��
+### 3. 定期数据同步
```csharp
var timer = new TimerX(async _ =>
{
var data = await FetchDataFromApiAsync();
await SaveToDatabase(data);
- Console.WriteLine("����ͬ�����");
-}, null, 0, 300000); // ÿ5����ͬ��һ��
+ Console.WriteLine("数据同步完成");
+}, null, 0, 300000); // 每5分钟同步一次
```
-### 4. �����ն�ʱ����
+### 4. 工作日定时报表
```csharp
-// ÿ������������9�����ɱ���
+// 每个工作日早上9点生成报表
var timer = new TimerX(_ =>
{
var report = GenerateReport(DateTime.Today.AddDays(-1));
SendEmail(report);
- Console.WriteLine("�����ѷ���");
+ Console.WriteLine("报表已发送");
}, null, "0 0 9 * * 1-5");
```
-### 5. ���ڽ������
+### 5. 定期健康检查
```csharp
var timer = new TimerX(_ =>
@@ -558,34 +558,34 @@ var timer = new TimerX(_ =>
var healthy = CheckSystemHealth();
if (!healthy)
{
- SendAlert("ϵͳ�쳣");
+ SendAlert("系统异常");
}
-}, null, 0, 30000); // ÿ30����һ��
+}, null, 0, 30000); // 每30秒检查一次
```
---
-## ���ʵ��
+## 最佳实践
-### 1. �첽�ص�����
+### 1. 异步回调优先
-���ں�ʱ������ʹ���첽�ص�����������
+对于耗时操作,使用异步回调避免阻塞:
```csharp
-// �Ƽ�
+// 推荐
var timer = new TimerX(async _ =>
{
await DoHeavyWorkAsync();
}, null, 0, 5000);
-// ���Ƽ�
+// 不推荐
var timer2 = new TimerX(_ =>
{
- DoHeavyWork(); // �����߳�
+ DoHeavyWork(); // 阻塞线程
}, null, 0, 5000);
```
-### 2. �����ͷ���Դ
+### 2. 主动释放资源
```csharp
public class MyService : IDisposable
@@ -599,28 +599,28 @@ public class MyService : IDisposable
public void Dispose()
{
- _timer?.Dispose(); // �ͷŶ�ʱ��
+ _timer?.Dispose(); // 释放定时器
}
}
```
-### 3. ʹ�� Current ����
+### 3. 使用 Current 属性
-�ڻص��п��Է��ʵ�ǰ��ʱ����
+在回调中可以访问当前定时器:
```csharp
var timer = new TimerX(_ =>
{
var current = TimerX.Current;
- Console.WriteLine($"��ʱ��[{current.Id}]��{current.Timers}��ִ��");
+ Console.WriteLine($"定时器[{current.Id}]第{current.Timers}次执行");
- // ��̬��������
+ // 动态调整周期
if (current.Timers > 10)
current.Period = 10000;
}, null, 0, 5000);
```
-### 4. ������
+### 4. 错误处理
```csharp
var timer = new TimerX(_ =>
@@ -631,131 +631,131 @@ var timer = new TimerX(_ =>
}
catch (Exception ex)
{
- Console.WriteLine($"��ʱ�����쳣��{ex.Message}");
- // ��¼��־����Ҫ�׳��쳣
+ Console.WriteLine($"定时任务异常:{ex.Message}");
+ // 记录日志,不要抛出异常
}
}, null, 0, 5000);
```
-### 5. Cron ���ӳ���
+### 5. Cron 复杂场景
```csharp
-// ����������9�㣬��������10��
+// 工作日早上9点,周六早上10点
var crons = "0 0 9 * * 1-5;0 0 10 * * 6";
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִ������");
+ Console.WriteLine("执行任务");
}, null, crons);
```
---
-## ע������
+## 注意事项
-### 1. ���������ͷ�
+### 1. 必须主动释放
```csharp
var timer = new TimerX(_ => { }, null, 0, 5000);
-// ... ʹ�� ...
-timer.Dispose(); // ������ã������ڴ�й©
+// ... 使用 ...
+timer.Dispose(); // 必须调用,否则内存泄漏
```
-### 2. Delay ����������
+### 2. Delay 方法的陷阱
```csharp
-// ����timer���ܱ�GC����
-TimerX.Delay(_ => Console.WriteLine("ִ��"), 10000);
+// 错误:timer可能被GC回收
+TimerX.Delay(_ => Console.WriteLine("执行"), 10000);
-// ��ȷ����������
-var timer = TimerX.Delay(_ => Console.WriteLine("ִ��"), 10000);
-// ... ����timer���������� ...
+// 正确:保持引用
+var timer = TimerX.Delay(_ => Console.WriteLine("执行"), 10000);
+// ... 保持timer在作用域内 ...
```
-### 3. ����ʱ�䲻����
+### 3. 绝对时间不可修改
```csharp
var timer = new TimerX(_ => { }, null, DateTime.Today.AddHours(2), 86400000);
-timer.SetNext(1000); // ��Ч
-timer.Change(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5)); // ���� false
+timer.SetNext(1000); // 无效
+timer.Change(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5)); // 返回 false
```
-### 4. State ��������
+### 4. State 是弱引用
```csharp
var obj = new MyObject();
var timer = new TimerX(_ =>
{
- var state = _.State as MyObject; // ����Ϊ null
+ var state = _.State as MyObject; // 可能为 null
}, obj, 0, 5000);
-// ��� obj �� GC ���գ�State ���Ϊ null
+// 如果 obj 被 GC 回收,State 会变为 null
```
-### 5. ����Ϊ0ִֻ��һ��
+### 5. 周期为0只执行一次
```csharp
var timer = new TimerX(_ =>
{
- Console.WriteLine("ִֻ��һ��");
-}, null, 1000, 0); // Period=0��ִֻ��һ��
+ Console.WriteLine("只执行一次");
+}, null, 1000, 0); // Period=0,只执行一次
```
---
-## ��������
+## 常见问题
-### 1. ��ʱ����ִ�У�
+### 1. 定时器不执行?
-��飺
-- �Ƿ� GC ���գ��������ã�
-- �Ƿ��� Dispose
-- Period �Ƿ�Ϊ����
-- Cron ����ʽ�Ƿ���ȷ
+检查:
+- 是否被 GC 回收(保持引用)
+- 是否已 Dispose
+- Period 是否为负数
+- Cron 表达式是否正确
-### 2. ��ʱ��ִ���˶�Σ�
+### 2. 定时器执行了多次?
-TimerX �Dz�������ģ��������������⡣������֣�����Ƿ��˶����ʱ��ʵ����
+TimerX 是不可重入的,不会出现这个问题。如果出现,检查是否创建了多个定时器实例。
-### 3. ���ֹͣ��ʱ����
+### 3. 如何停止定时器?
```csharp
-timer.Dispose(); // ���ٲ��Ƴ�
+timer.Dispose(); // 销毁并移除
```
-### 4. �����ͣ�ͻָ���
+### 4. 如何暂停和恢复?
```csharp
-// ��ͣ������Ϊִֻ��һ�Σ�
+// 暂停(设置为只执行一次)
timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
-// �ָ�
+// 恢复
timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(5));
```
-### 5. Cron �;���ʱ�������
+### 5. Cron 和绝对时间的区别?
-| ���� | Cron | ����ʱ�� |
+| 特性 | Cron | 绝对时间 |
|-----|------|---------|
-| ����ʽ | ֧�ָ��ӹ��� | �̶�ʱ��+���� |
-| ����� | �ߣ��뼶�����ڵȣ� | �ͣ��̶����ڣ� |
-| ���� | �Եͣ�������� | �� |
-| ���ó��� | ���Ӷ�ʱ | ������ |
+| 表达式 | 支持复杂规则 | 固定时刻+周期 |
+| 灵活性 | 高(秒级、星期等) | 低(固定周期) |
+| 性能 | 略低(需解析) | 高 |
+| 适用场景 | 复杂定时 | 简单周期 |
---
-## �����
+## 参考资料
-- **Cron �ĵ�**: [cron-Cron����ʽ.md](cron-Cron����ʽ.md)
-- **��·��**: [tracer-��·��ITracer.md](tracer-��·��ITracer.md)
-- **�����ĵ�**: https://newlifex.com/core/timerx
-- **Դ��**: https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/TimerX.cs
+- **Cron 文档**: [cron-Cron表达式.md](cron-Cron表达式.md)
+- **链路追踪**: [tracer-链路追踪ITracer.md](tracer-链路追踪ITracer.md)
+- **在线文档**: https://newlifex.com/core/timerx
+- **源码**: https://github.com/NewLifeX/X/blob/master/NewLife.Core/Threading/TimerX.cs
---
-## ������־
+## 更新日志
-- **2025-01**: �����ĵ���������ϸʾ�������ʵ��
-- **2024**: ֧�� .NET 9.0���Ż�����
-- **2023**: ���� Cron �����ʽ֧��
-- **2022**: �����첽�ص�֧��
-- **2020**: ��ʼ�汾������ TickCount �ľ���ʱ
+- **2025-01**: 完善文档,补充详细示例和最佳实践
+- **2024**: 支持 .NET 9.0,优化性能
+- **2023**: 增加 Cron 多表达式支持
+- **2022**: 增加异步回调支持
+- **2020**: 初始版本,基于 TickCount 的精准计时