# dmfExtension.Core **Repository Path**: dmfsmile/dmfExtension.Core ## Basic Information - **Project Name**: dmfExtension.Core - **Description**: .net工具 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-29 - **Last Updated**: 2026-06-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # dmfExtension.Core .NET 工具库核心模块,对标 Java Hutool,提供字符串、集合、日期、对象、随机数、ID 生成、正则表达式、反射、枚举、DataTable、日志等日常开发常用工具方法。 ## 目标框架 | 框架 | 版本 | 备注 | |------|------|------| | .NET | 8.0+ | C# 12, 可空引用类型 | | .NET Standard | 2.0 | 兼容 .NET Framework 4.6.1+, C# 10 | > `#if NET8_0` 条件编译用于在 net8.0 下提供优化实现(如 `Random.Shared`、`System.HashCode`、`RandomNumberGenerator.Fill`)并在 netstandard2.0 下回退到兼容实现。 ## 项目结构 ``` dmfExtension.Core/ ├── Extensions/ # 扩展方法(链式调用) │ ├── ObjectExtensions.cs │ └── StringExtensions.cs ├── Utils/ # 静态工具类 │ ├── StringUtil.cs # 字符串判空/截取/格式化/命名转换/脱敏 │ ├── CollectionUtil.cs # 集合判空/创建/操作/分区/字典 │ ├── DateUtil.cs # 日期格式化/解析/运算/比较/年龄/工作日 │ ├── ObjectUtil.cs # 对象判空/比较/类型检查/转换 │ ├── RandomUtil.cs # 随机数/字符串/安全随机 │ ├── IdUtil.cs # UUID/Snowflake/ObjectId │ ├── DataTableUtil.cs # DataTable 创建/查询/转换/合并 │ ├── LogUtil.cs # 日志(委托注入,零依赖) │ ├── RegexUtil.cs # 正则匹配/验证/查找/替换 │ ├── ReflectUtil.cs # 反射属性/字段/方法/实例/特性 │ └── EnumUtil.cs # 枚举转换/描述/列表 ├── Models/ │ ├── ConversionResult.cs # 泛型转换结果 │ ├── EnumItem.cs # 枚举项(值+名+描述+整数值) │ └── SelectItem.cs # 下拉选择项(值+文本) └── README.md ``` --- # API 完整参考 ## 1. StringUtil 字符串工具类,提供判空、截取、格式化、命名转换、脱敏等操作。 ### 判空 | 方法 | 说明 | null | "" | " " | "abc" | |------|------|------|-----|-----|-------| | `IsNullOrEmpty(str)` | 是否为 null 或空字符串 | true | true | false | false | | `IsNullOrWhiteSpace(str)` | 是否为 null 或空白 | true | true | true | false | | `IsNotEmpty(str)` | 是否不为空 | false | false | true | true | | `IsNotBlank(str)` | 是否不为空白 | false | false | false | true | ### 截取 | 方法 | 说明 | 示例 | |------|------|------| | `Substring(str, start, length)` | 安全截取(越界返回空串) | `Substring("abcdef", 1, 3)` → `"bcd"` | | `SubstringBefore(str, char)` | 截取指定字符之前 | `SubstringBefore("a/b/c", '/')` → `"a"` | | `SubstringBefore(str, string)` | 截取指定字符串之前 | `SubstringBefore("abc/def", "/")` → `"abc"` | | `SubstringAfter(str, char)` | 截取指定字符之后 | `SubstringAfter("a/b/c", '/')` → `"b/c"` | | `SubstringAfter(str, string)` | 截取指定字符串之后 | `SubstringAfter("abc/def", "/")` → `"def"` | | `SubstringBetween(str, before, after)` | 截取两个字符串之间 | `SubstringBetween("{abc}", "{", "}")` → `"abc"` | > `SubstringBefore/After/Between` 的 `string` 参数不接受 null,传入 null 抛出 `ArgumentNullException`。 ### 格式化 | 方法 | 说明 | 示例 | |------|------|------| | `Format(template, args...)` | 顺序替换 `{0} {1}` 占位符 | `Format("{0}岁,{1}", 25, "男")` → `"25岁,男"` | | `Join(separator, parts...)` | 连接字符串数组 | `Join(",", "a", "b", "c")` → `"a,b,c"` | | `Join(separator, items)` | 连接泛型集合 | `Join("-", new[]{1,2,3})` → `"1-2-3"` | | `Join(separator, items, converter)` | 带转换器连接 | `Join("-", list, s=>s.ToUpper())` | | `Repeat(str, count)` | 重复字符串 | `Repeat("abc", 3)` → `"abcabcabc"` | | `PadLeft/Right(str, width, char)` | 填充对齐 | `PadLeft("abc", 5)` → `" abc"` | > `Format` 方法按索引顺序替换,不是完整的 `string.Format` 实现。如果参数值中包含 `{N}` 模式,它会被替换,请注意避免。 ### 命名转换 | 方法 | 说明 | 示例 | |------|------|------| | `ToCamelCase(str)` | 驼峰 | `"HelloWorld"` → `"helloWorld"` | | `ToPascalCase(str)` | 帕斯卡 | `"helloWorld"` → `"HelloWorld"` | | `ToSnakeCase(str)` | 蛇形 | `"HelloWorld"` → `"hello_world"` | | `ToKebabCase(str)` | 短横线 | `"HelloWorld"` → `"hello-world"` | | `FirstUpper(str)` | 首字母大写 | 同 `ToPascalCase` | | `FirstLower(str)` | 首字母小写 | 同 `ToCamelCase` | ### 脱敏 | 方法 | 说明 | 示例 | |------|------|------| | `Mask(str, start, length, char)` | 通用掩码 | `Mask("abcdef", 2, 3)` → `"ab***f"` | | `MaskPhone(phone)` | 手机号 | `"13812345678"` → `"138****5678"` | | `MaskEmail(email)` | 邮箱 | `"test@example.com"` → `"te***@example.com"` | | `MaskIdCard(idCard)` | 身份证 | `"110101199001011234"` → `"1101**********1234"` | | `MaskBankCard(cardNumber)` | 银行卡 | `"6222021234563456"` → `"6222 **** **** 3456"` | --- ## 2. StringExtensions 为 `StringUtil` 方法提供链式调用扩展。 ```csharp using dmfExtension.Core.Extensions; "abc".IsNullOrEmpty(); // false "HelloWorld".ToSnakeCase(); // "hello_world" "13812345678".MaskPhone(); // "138****5678" "test@example.com".MaskEmail(); // "te***@example.com" ``` --- ## 3. CollectionUtil 集合工具类,提供判空、创建、分区、字典操作等。 ### 判空与创建 | 方法 | 说明 | |------|------| | `IsNullOrEmpty(collection)` | 判断集合是否为 null 或空 | | `IsNotEmpty(collection)` | 判断集合是否不为空 | | `NewList(items...)` | 从参数创建 `List` | | `NewSet(items...)` | 从参数创建 `HashSet` | | `NewMap()` | 创建空 `Dictionary` | | `NewMap(pairs)` | 从键值对创建字典 | | `AddAll(list, items...)` | 批量添加元素到列表 | ### 集合操作 | 方法 | 说明 | 示例 | |------|------|------| | `RemoveNull(collection)` | 移除所有 null 元素 | 仅支持引用类型 | | `Distinct(collection)` | 去重 | 保留首次出现的顺序 | | `DistinctBy(collection, keySelector)` | 按键去重 | | | `UnionAll(collections...)` | 合并多个集合 | 惰性求值,`yield return` | ### 分区 | 方法 | 说明 | 示例 | |------|------|------| | `Partition(source, size)` | 按大小分区 | `Partition([1,2,3,4,5], 2)` → `[[1,2],[3,4],[5]]` | | `PartitionBy(source, predicate)` | 按谓词分区 | `PartitionBy([1,2,3,4], n=>n%2==0)` → `[[2,4],[1,3]]` | > `Partition` 的 `size` 参数必须大于 0,否则抛出 `ArgumentException`。 ### 字典操作 | 方法 | 说明 | 示例 | |------|------|------| | `GetOrDefault(dict, key, default)` | 安全取值 | 键不存在返回默认值 | | `GetOrCreate(dict, key, factory)` | 获取或创建 | 键不存在时由 factory 创建 | ### 获取 | 方法 | 说明 | |------|------| | `FirstOrDefault(source, default)` | 获取第一个元素 | | `LastOrDefault(source, default)` | 获取最后一个元素 | --- ## 4. DateUtil 日期时间工具类,提供格式化、解析、运算、比较、差值计算、年龄计算和工作日判断。 ### 格式常量 | 常量 | 值 | |------|-----| | `PATTERN_DATE` | `"yyyy-MM-dd"` | | `PATTERN_TIME` | `"HH:mm:ss"` | | `PATTERN_DATETIME` | `"yyyy-MM-dd HH:mm:ss"` | | `PATTERN_DATETIME_MS` | `"yyyy-MM-dd HH:mm:ss.fff"` | | `PATTERN_ISO` | `"yyyy-MM-ddTHH:mm:ss.fffZ"` | ### 当前时间 ```csharp DateUtil.Now(); // DateTime.Now DateUtil.Today(); // DateTime.Today DateUtil.UtcNow(); // DateTime.UtcNow ``` ### 格式化 ```csharp DateUtil.Format(new DateTime(2026, 6, 29), "yyyy/MM/dd"); // "2026/06/29" DateUtil.FormatDate(date); // "2026-06-29" DateUtil.FormatTime(date); // "15:30:05" DateUtil.FormatDateTime(date); // "2026-06-29 15:30:05" DateUtil.FormatISO(date); // "2026-06-29T15:30:05.123Z" ``` ### 解析 ```csharp DateUtil.Parse("2026-06-29", "yyyy-MM-dd"); // DateTime(2026,6,29) DateUtil.ParseDate("2026-06-29"); // DateTime(2026,6,29) DateUtil.ParseDateTime("2026-06-29 15:30:00"); DateUtil.TryParse("2026-06-29", "yyyy-MM-dd", out var result); // true ``` > 解析方法对所有输入参数做非空检查,无效输入抛出 `FormatException`。`TryParse` 安全返回 `bool`。 ### 日期运算 ```csharp DateUtil.AddDays(date, 10); // +10 天 DateUtil.AddMonths(date, 1); // +1 月 DateUtil.AddYears(date, 1); // +1 年 DateUtil.AddHours(date, 2); // +2 小时 DateUtil.AddMinutes(date, 30); // +30 分钟 DateUtil.AddSeconds(date, 45); // +45 秒 DateUtil.StartOfDay(date); // 当天 00:00:00.000 DateUtil.EndOfDay(date); // 当天 23:59:59.999 DateUtil.StartOfMonth(date); // 当月 1 日 00:00:00.000 DateUtil.EndOfMonth(date); // 当月最后一天 23:59:59.999 DateUtil.StartOfYear(date); // 当年 1 月 1 日 DateUtil.EndOfYear(date); // 当年 12 月 31 日 23:59:59.999 ``` > 所有运算保留 `date.Kind` 属性(Local/Utc/Unspecified)。 ### 比较 ```csharp DateUtil.Compare(d1, d2); // -1 / 0 / 1 DateUtil.IsSameDay(d1, d2); // 同一天 DateUtil.IsSameMonth(d1, d2); // 同一月 DateUtil.IsSameYear(d1, d2); // 同一年 DateUtil.IsLeapYear(2024); // true DateUtil.DaysInMonth(2024, 2); // 29 ``` ### 差值计算 ```csharp DateUtil.BetweenDays(start, end); // 天数差(绝对值) DateUtil.BetweenHours(start, end); // 小时差 DateUtil.BetweenMinutes(start, end); // 分钟差 DateUtil.BetweenSeconds(start, end); // 秒差 DateUtil.BetweenMilliseconds(start, end); // 毫秒差 ``` ### 年龄计算 ```csharp DateUtil.Age(new DateTime(1990, 1, 1)); // 基于今天 DateUtil.Age(new DateTime(1990, 1, 1), DateTime.Today); ``` ### 工作日判断 ```csharp DateUtil.IsWeekend(date); // 周六/日 → true DateUtil.IsWeekday(date); // 周一至周五 → true DateUtil.GetDayOfWeek(date); // DayOfWeek 枚举值 ``` --- ## 5. ObjectUtil ### 判空 | 方法 | 说明 | |------|------| | `IsNull(obj)` | 判断对象是否为 null | | `IsNotNull(obj)` | 判断对象是否不为 null | | `DefaultIfNull(obj, defaultValue)` | 为 null 时返回默认值 | | `DefaultIfNull(obj, factory)` | 为 null 时通过工厂创建 | ### 比较与哈希 | 方法 | 说明 | |------|------| | `Equals(o1, o2)` | 值相等比较 | | `DeepEquals(o1, o2)` | 递归属性比较(无循环引用保护) | | `HashCode(objects...)` | 多对象哈希组合 | ### 类型检查 | 方法 | 说明 | |------|------| | `IsNumber(obj)` | 是否为数字类型 | | `IsDateTime(obj)` | 是否为 DateTime | | `IsEnum(obj)` | 是否为枚举 | | `IsArray(obj)` | 是否为数组 | | `IsValueType(obj)` | 是否为值类型 | | `IsReferenceType(obj)` | 是否为引用类型 | ### 转换 | 方法 | 说明 | |------|------| | `As(obj)` | 安全转换,失败返回 `default(T)` | | `Cast(obj)` | 强制转换,失败抛 `InvalidCastException` | | `ToString(obj)` | null → `""` | | `ToString(obj, nullValue)` | null → 自定义字符串 | ### 克隆 | 方法 | 说明 | |------|------| | `Clone(obj)` | 要求实现 `ICloneable` | > `DeepClone` 已跳过(需要 `System.Text.Json` 依赖,按设计决策排除)。 --- ## 6. RandomUtil 随机数工具类,提供基础随机、字符串随机和安全随机。 ### 基础随机 | 方法 | 说明 | |------|------| | `RandomInt(min, max)` | [min, max) 随机整数 | | `RandomLong(min, max)` | [min, max) 随机长整数 | | `RandomDouble(min, max)` | [min, max) 随机双精度 | | `RandomFloat(min, max)` | [min, max) 随机单精度 | | `RandomBool()` | 随机 boolean | | `RandomItem(array)` | 随机选取数组元素 | | `RandomItem(enumerable)` | 随机选取集合元素 | > `min` 必须小于 `max`,否则抛出 `ArgumentException`。 ### 字符串随机 | 方法 | 说明 | |------|------| | `RandomString(length)` | 随机字母数字字符串 | | `RandomString(length, chars)` | 从指定字符集随机 | | `RandomNumber(length)` | 纯数字字符串 | | `RandomChinese(length)` | 随机中文字符串 | | `RandomChineseName()` | 随机中文姓名 | | `RandomEmail()` | 随机邮箱地址 | | `RandomPhone()` | 随机手机号(中国大陆前缀) | ### 安全随机 | 方法 | 说明 | |------|------| | `SecureRandomBytes(length)` | 加密级随机字节 | | `SecureRandomString(length)` | 加密级随机字符串(无模偏倚) | > `SecureRandomBytes` 使用 `System.Security.Cryptography.RandomNumberGenerator`。`SecureRandomString` 使用拒绝采样法避免模偏倚。`net8.0` 下使用 `Random.Shared`,`netstandard2.0` 下使用线程局部 `Random`。 --- ## 7. IdUtil 唯一 ID 生成工具类,提供 UUID、Snowflake 和 ObjectId。 ### UUID | 方法 | 说明 | 示例 | |------|------|------| | `UUID()` | 标准 UUID | `"550e8400-e29b-41d4-a716-446655440000"` | | `SimpleUUID()` | 无横线 UUID | `"550e8400e29b41d4a716446655440000"` | | `ShortUUID()` | 8 位 Base62 短 ID | `"1aB3xY9z"`(非唯一保证) | ### Snowflake | 方法 | 说明 | |------|------| | `SnowflakeId()` | 生成 Snowflake ID (long) | | `SnowflakeId(workerId, dataCenterId)` | 指定配置生成(同时更新全局配置) | | `SnowflakeIdString()` | 字符串形式 | | `ConfigureSnowflake(workerId, dataCenterId)` | 预设 workerId/datacenterId | > 默认 `workerId=1, dataCenterId=1`。`workerId` 范围 [0, 31],`dataCenterId` 范围 [0, 31]。系统时钟回拨时抛出 `InvalidOperationException`。 ### ObjectId | 方法 | 说明 | |------|------| | `ObjectId()` | 生成 24 位十六进制 ObjectId | | `ObjectIdTimestamp(id)` | 从 ObjectId 提取时间戳 | > 实现格式:4 字节时间戳 + 2 字节机器 ID + 2 字节进程 ID + 3 字节自增计数器 + 1 字节填充。 --- ## 8. DataTableUtil DataTable 操作工具类。 ### 创建 | 方法 | 说明 | |------|------| | `NewTable(name)` | 创建 DataTable | | `NewTable(name, columns...)` | 从列名数组创建 | | `AddColumn(table, name, type)` | 添加列 | ### 行操作 | 方法 | 说明 | |------|------| | `AddRow(table, values...)` | 添加行 | | `RemoveRow(table, index)` | 移除行 | ### 查询 | 方法 | 说明 | |------|------| | `Select(table, filter)` | 按筛选表达式查询 | | `FirstRow(table)` | 第一行 | | `LastRow(table)` | 最后一行 | | `FindRow(table, filter)` | 匹配的第一行 | ### 转换 | 方法 | 说明 | |------|------| | `ToList(table, converter)` | 转为 List | | `ToDictionary(table, keySelector, valueSelector)` | 转为字典 | | `ToJson(table)` | 转为 JSON 字符串 | > `ToJson` 输出所有值为字符串类型。特殊字符(`"` `\` `\n` `\r` `\t`)已正确转义。 ### 判断与合并 | 方法 | 说明 | |------|------| | `IsNullOrEmpty(table)` | 是否为 null 或无行 | | `IsNotEmpty(table)` | 是否有行 | | `Merge(tables...)` | 合并多个 DataTable | --- ## 9. LogUtil 日志工具类,基于委托注入,零外部依赖。 ### 级别 ```csharp LogLevel.Trace < Debug < Info < Warn < Error < Fatal ``` ### 配置 ```csharp LogUtil.SetLogger((level, msg, ex) => { /* 自定义处理 */ }); LogUtil.SetMinLevel(LogLevel.Warn); // 只记录 Warn 及以上 LogUtil.UseConsole(); // 内置控制台输出 LogUtil.UseTrace(); // 内置 Trace 输出 ``` ### 日志方法 ```csharp LogUtil.Trace("msg"); LogUtil.Debug("msg"); LogUtil.Info("msg"); LogUtil.Warn("msg"); LogUtil.Error("msg"); LogUtil.Error(exception); // 记录异常 LogUtil.Error(exception, "context"); LogUtil.Fatal("msg"); LogUtil.Fatal(exception, "context"); ``` ### 级别检查 ```csharp LogUtil.IsTraceEnabled LogUtil.IsDebugEnabled LogUtil.IsInfoEnabled LogUtil.IsWarnEnabled LogUtil.IsErrorEnabled LogUtil.IsFatalEnabled ``` --- ## 10. RegexUtil 正则表达式工具类,提供常用验证和操作。 ### 匹配 | 方法 | 说明 | |------|------| | `IsMatch(str, pattern)` | 是否匹配 | | `IsMatch(str, pattern, options)` | 指定选项匹配 | ### 常用验证 | 方法 | 说明 | |------|------| | `IsEmail(str)` | 邮箱格式 | | `IsPhone(str)` | 中国大陆手机号(1[3-9] 开头) | | `IsIdCard(str)` | 中国大陆身份证(18 位,含日期校验) | | `IsPassport(str)` | 护照号 | | `IsIpAddress(str)` | IPv4 或 IPv6 | | `IsIpV4Address(str)` | IPv4 | | `IsIpV6Address(str)` | IPv6 | | `IsUrl(str)` | HTTP/HTTPS URL | | `IsDomain(str)` | 域名 | | `IsChinese(str)` | 纯中文 | | `IsChineseName(str)` | 中文姓名(2-4 字) | | `IsEnglish(str)` | 纯英文字母 | | `IsNumeric(str)` | 数字(含小数) | | `IsLetter(str)` | 纯字母 | | `IsAlphanumeric(str)` | 字母数字 | | `IsHexColor(str)` | 十六进制颜色(#RRGGBB) | | `IsDate(str, format)` | 指定格式日期 | | `IsDateTime(str, format)` | 指定格式日期时间 | > 所有验证方法对 null 输入返回 `false`。 ### 查找与替换 | 方法 | 说明 | |------|------| | `Find(str, pattern)` | 第一个匹配 | | `Find(str, pattern, groupIndex)` | 指定分组 | | `FindAll(str, pattern)` | 所有匹配 | | `FindAll(str, pattern, groupIndex)` | 所有匹配的指定分组 | | `Replace(str, pattern, replacement)` | 替换 | | `Replace(str, pattern, evaluator)` | 带评估器替换 | ### 转义 | 方法 | 说明 | |------|------| | `Escape(str)` | 转义正则特殊字符 | | `Unescape(str)` | 反转义 | --- ## 11. ReflectUtil 反射工具类,提供属性、字段、方法、实例、特性操作。 ### 属性操作 | 方法 | 说明 | |------|------| | `GetProperty(type, name)` | 获取属性信息 | | `GetPropertyValue(obj, name)` | 获取属性值(支持嵌套 `"A.B.C"`) | | `SetPropertyValue(obj, name, value)` | 设置属性值 | | `GetProperties(obj)` | 获取所有属性和值 | | `SetProperties(obj, dict)` | 批量设值 | > `SetPropertyValue` 对点分路径的中间节点为 null 时抛出 `InvalidOperationException`,对只读属性抛出 `InvalidOperationException`。 ### 字段操作 | 方法 | 说明 | |------|------| | `GetField(type, name)` | 获取字段信息 | | `GetFieldValue(obj, name)` | 获取字段值 | | `SetFieldValue(obj, name, value)` | 设置字段值 | ### 方法调用 | 方法 | 说明 | |------|------| | `InvokeMethod(obj, name, args...)` | 调用实例方法 | | `InvokeMethod(obj, name, types, args)` | 指定参数类型调用 | | `InvokeStaticMethod(type, name, args...)` | 调用静态方法 | ### 实例创建 | 方法 | 说明 | |------|------| | `NewInstance(args...)` | 创建泛型实例 | | `NewInstance(type, args...)` | 创建指定类型实例 | ### 类型与特性 | 方法 | 说明 | |------|------| | `GetType(name)` | 按名称获取类型 | | `HasAttribute(member, attrType)` | 判断是否有特性 | | `GetAttribute(member)` | 获取特性实例 | | `GetAttributes(member)` | 获取所有特性 | --- ## 12. EnumUtil ### 转换 | 方法 | 说明 | |------|------| | `FromString(str)` | 字符串解析枚举 | | `FromString(str, ignoreCase)` | 忽略大小写解析 | | `FromInt(intValue)` | 整数值转枚举 | | `FromDescription(description)` | DescriptionAttribute 值转枚举 | ### 获取信息 | 方法 | 说明 | |------|------| | `GetDescription(value)` | 获取 DescriptionAttribute | | `GetName(value)` | 获取枚举名称 | | `GetValue(value)` | 获取整数值 | | `GetItems()` | 获取所有项(含描述) | ### 检查 | 方法 | 说明 | |------|------| | `IsDefined(value)` | 枚举值是否已定义 | | `IsDefined(str)` | 字符串是否对应已定义值 | | `IsDefined(intValue)` | 整数值是否对应已定义值 | ### 列表 | 方法 | 说明 | |------|------| | `GetValues()` | 获取所有值 | | `GetNames()` | 获取所有名称 | | `ToSelectItems()` | 转为下拉选择列表 | ```csharp public enum Status { [Description("待处理")] Pending = 0, [Description("进行中")] Processing = 1, [Description("已完成")] Completed = 2 } EnumUtil.GetDescription(Status.Pending); // "待处理" EnumUtil.FromDescription("待处理"); // Status.Pending EnumUtil.GetItems(); // [{Value=Pending, Name="Pending", Description="待处理", IntValue=0}, ...] ``` --- # 条件编译说明 文件使用 `#if NET8_0` / `#else / #endif` 在以下位置处理两框架差异: | 特性 | net8.0 | netstandard2.0 | |------|--------|----------------| | `Dictionary(IEnumerable>)` | 原生支持 | 手动循环添加 | | `System.HashCode` | `System.HashCode` | 手动 `unchecked` 算术 | | `Random` 实例 | `Random.Shared`(线程安全) | `[ThreadStatic]` + 锁初始化 | | `RandomNumberGenerator.Fill(byte[])` | `Fill` | `rng.GetBytes` | | `Environment.ProcessId` | 可用 | `Process.GetCurrentProcess().Id` | # 构建与测试 ```bash # 构建主库(双框架) dotnet build dmfExtension.Core/dmfExtension.Core.csproj # 运行单元测试 dotnet test dmfExtension.Core.Tests/dmfExtension.Core.Tests.csproj # 查看测试覆盖率 dotnet test dmfExtension.Core.Tests/dmfExtension.Core.Tests.csproj --collect:"XPlat Code Coverage" ``` # 测试覆盖率 现有 **272 个测试用例**,覆盖全部 10 个工具类和 2 个扩展类: | 模块 | 测试数 | |------|--------| | StringUtil | 45 | | CollectionUtil | 25 | | DateUtil | 28 | | ObjectUtil | 28 | | RandomUtil | 20 | | IdUtil | 16 | | DataTableUtil | 23 | | LogUtil | 10 | | RegexUtil | 34 | | ReflectUtil | 18 | | EnumUtil | 18 | | **合计** | **272** |