RuoVea.ExUtil 10.0.0.4

dotnet add package RuoVea.ExUtil --version 10.0.0.4
                    
NuGet\Install-Package RuoVea.ExUtil -Version 10.0.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RuoVea.ExUtil" Version="10.0.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RuoVea.ExUtil" Version="10.0.0.4" />
                    
Directory.Packages.props
<PackageReference Include="RuoVea.ExUtil" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RuoVea.ExUtil --version 10.0.0.4
                    
#r "nuget: RuoVea.ExUtil, 10.0.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RuoVea.ExUtil@10.0.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RuoVea.ExUtil&version=10.0.0.4
                    
Install as a Cake Addin
#tool nuget:?package=RuoVea.ExUtil&version=10.0.0.4
                    
Install as a Cake Tool

🔧 RuoVea.ExUtil

通用 .NET 工具库 — 涵盖类型转换、JSON 序列化、日期格式化、数据验证、HTTP 请求、控制台输出、表达式树构建、汉字拼音、系统监控、Shell 命令等 15+ 个模块,提供丰富的 object / string 扩展方法与静态工具类,并内置中、英、法、日、粤语、越南语等 7 种语言的异常提示。


📖 目录


📋 概览

RuoVea.ExUtil 为 .NET 开发者提供了日常开发所需的基础工具集,避免在类型转换、JSON 序列化、参数校验等通用逻辑上重复造轮子。

 ┌──────────────────────────────────────────────────────────┐
 │                    RuoVea.ExUtil                          │
 ├──────────────────────────────────────────────────────────┤
 │  类型转换        字符串处理        JSON 序列化            │
 │  ├─ ToInt       ├─ FirstUpper    ├─ Json2Str            │
 │  ├─ ToDouble    ├─ ToCamel       ├─ ToObject<T>         │
 │  ├─ ToDecimal   ├─ ContainsChinese├─ ToList<T>           │
 │  ├─ ToDate      ├─ FilterEmoji   ├─ DataTableToJson      │
 │  ├─ ToBool      ├─ Truncate      └─ LongToStringConverter│
 │  └─ GetBytes    └─ StrToListLong                         │
 │                                                          │
 │  数据验证        日期格式化        HTTP / 网络             │
 │  ├─ Valid (80+) ├─ ToDateTimeS.. ├─ HttpPost / HttpGet   │
 │  ├─ Check (16)  ├─ ToChineseDate ├─ GetLanIp             │
 │  └─ Attributes  ├─ GetTimeStamp  └─ UrlEncode            │
 │                 └─ UnixTime                              │
 │                                                          │
 │  表达式树        系统监控          拼音 / 唯一标识          │
 │  ├─ And / Or    ├─ ExMachine     ├─ PinYin               │
 │  ├─ True / False├─ ExShell       ├─ Unique               │
 │  └─ Compose     └─ ConsoleHelper └─ CreateNo             │
 ├──────────────────────────────────────────────────────────┤
 │  国际化: zh-CN | zh-TW | zh-HK | en-US | fr-FR | ja-JP | vi-VN │
 └──────────────────────────────────────────────────────────┘

设计原则

原则 说明
全静态访问 所有工具方法均为 static,无需实例化、无需 DI 注册
扩展方法优先 this 扩展方法为主要入口,提供流畅的链式调用体验
容错返回 类型转换方法在失败时返回默认值(0 / false / null),不抛异常
参数校验内置 Check 类提供带本地化异常消息的参数校验,自动抛出 ArgumentException

📦 安装

.NET CLI

# .NET 8.0
dotnet add package RuoVea.ExUtil --version 8.0.1.4

# .NET 10.0
dotnet add package RuoVea.ExUtil --version 10.0.0.3

Package Manager

Install-Package RuoVea.ExUtil -Version 8.0.1.4

PackageReference

<PackageReference Include="RuoVea.ExUtil" Version="8.0.1.4" />

依赖项

依赖包 版本 说明
Newtonsoft.Json 13.0.4 JSON 序列化/反序列化核心依赖

支持的 Target Framework

TFM 最低版本
net8.0 8.0.1.4
net10.0 10.0.0.3

⚡ 30 秒快速开始

1. 导入命名空间

using RuoVea.ExUtil;               // 扩展方法、Common、ConsoleHelper、LinqExtensions、HttpUtils
using RuoVea.ExUtil.Validate;      // Valid 验证类
using RuoVea.ExUtil.ExString;      // Str(拼音、唯一标识)
using RuoVea.ExUtil.Time;          // UnixTime
using RuoVea.ExUtil.Machine;       // ExMachine、ExShell

2. 第一行工具代码

// <inheritdoc cref="Extensions.ToInt(object)"/>
// 类型转换 — 失败返回默认值,不抛异常
int age = "25".ToInt();                    // 25
int invalid = "abc".ToInt();               // 0

// <inheritdoc cref="Extensions.GetTimeStamp(DateTime)"/>
// 日期格式化 — 获取当前时间戳
long timestamp = DateTime.Now.GetTimeStamp();

// <inheritdoc cref="Valid.IsEmail(string, bool)"/>
// 数据验证 — 邮箱格式校验
bool isEmail = Valid.IsEmail("test@example.com");  // true

3. 使用扩展方法(更流畅)

// <inheritdoc cref="Extensions.ToDateTimeString(DateTime, bool)"/>
string now = DateTime.Now.ToDateTimeString();          // "2024-01-01 12:30:45"

// <inheritdoc cref="Extensions.ContainsChinese(string)"/>
bool hasCn = "Hello中国".ContainsChinese();            // true

// <inheritdoc cref="Extensions.ToObject{T}(string)"/>
var user = "{\"Name\":\"张三\"}".ToObject<User>();

// <inheritdoc cref="Str.PinYin(string)"/>
string py = Str.PinYin("中国");                        // "zg"

30 秒内你完成了: 类型安全转换 → 时间戳获取 → 邮箱格式校验 → 日期格式化 → 中文检测 → JSON 反序列化 → 拼音转换。


🧩 核心场景

场景一:类型转换(Convert 扩展)

┌──────────┐     ToInt() / ToDouble() / ToDate()     ┌──────────────┐
│  object   │ ────────────────────────────────────▶  │  目标类型      │
│ (任意输入) │     失败时返回默认值,不抛异常             │  (int/double…) │
└──────────┘                                         └──────────────┘
用例: 处理外部数据源(HTTP 参数、数据库结果、CSV)的类型安全转换
数值转换
// <inheritdoc cref="Extensions.ToInt(object)"/>
int i1 = "123".ToInt();                  // 123
int i2 = "12.8".ToInt();                 // 13(先转 double 再取整)
int i3 = "abc".ToInt();                  // 0(容错返回默认值)
int? ni = "".ToIntOrNull();              // null

// <inheritdoc cref="Extensions.ToDouble(object)"/>
double d1 = "3.14".ToDouble();           // 3.14
double d2 = "3.14159".ToDouble(2);       // 3.14(四舍五入到指定小数位)

// <inheritdoc cref="Extensions.ToDecimal(object)"/>
decimal m1 = "99.99".ToDecimal();        // 99.99
decimal? mn = "".ToDecimalOrNull();      // null
日期与布尔转换
// <inheritdoc cref="Extensions.ToDate(object)"/>
DateTime dt1 = "2024-01-01".ToDate();    // 2024-01-01
DateTime dt2 = "20240101".ToDate();      // 支持 yyyyMMdd 格式
DateTime dt3 = "invalid".ToDate();       // DateTime.MinValue

DateTime? dtN = "".ToDateOrNull();       // null

// <inheritdoc cref="Extensions.ToBool(object)"/>
bool b1 = "true".ToBool();               // true
bool b2 = "是".ToBool();                 // true(支持中文)
bool b3 = "0".ToBool();                  // false
bool b4 = "yes".ToBool();                // true(支持英文)
字典与字节转换
// <inheritdoc cref="Extensions.ToQueryString(Dictionary{string, string}, bool)"/>
var dict = new Dictionary<string, string> { ["name"] = "张三", ["age"] = "25" };
string qs = dict.ToQueryString();        // "name=%E5%BC%A0%E4%B8%89&age=25"

// <inheritdoc cref="Extensions.GetBytes(string)"/>
byte[] bytes = "Hello".GetBytes();       // UTF-8 编码

// <inheritdoc cref="Extensions.UrlEncode(string)"/>
string encoded = "张三".UrlEncode();     // "%E5%BC%A0%E4%B8%89"

注意事项: ToDate 在转换失败时返回 DateTime.MinValue 而非 null,如需可空判断请使用 ToDateOrNull


场景二:JSON 序列化与反序列化

┌──────────┐   Json2Str() / Serialize()    ┌──────────────┐
│  对象      │ ──────────────────────────▶  │  JSON 字符串   │
│  / 字典    │                               │               │
└──────────┘                               └──────┬───────┘
                                                  │
                             ToObject<T>() / ToList<T>() / ToJObject()
                                                  │
                                                  ▼
                                          ┌──────────────┐
                                          │  强类型对象    │
                                          └──────────────┘
// <inheritdoc cref="Extensions.Json2Str(object, bool)"/>
var obj = new { Name = "张三", Age = 25 };
string json = obj.Json2Str();            // {"Name":"张三","Age":25}(默认 yyyy-MM-dd HH:mm:ss)

// <inheritdoc cref="Extensions.Json2Str(object, string, bool)"/>
string json2 = obj.Json2Str("yyyyMMdd"); // 自定义日期格式

// <inheritdoc cref="Extensions.ToObject{T}(string)"/>
var user = "{\"Name\":\"李四\",\"Age\":30}".ToObject<User>();

// <inheritdoc cref="Extensions.ToList{T}(string)"/>
var list = "[{\"Name\":\"A\"},{\"Name\":\"B\"}]".ToList<User>();

// <inheritdoc cref="Extensions.ToJObject(string)"/>
JObject jo = "{\"key\":\"value\"}".ToJObject();

// <inheritdoc cref="Extensions.DataTableToJson(DataTable)"/>
string dtJson = dataTable.DataTableToJson();

// <inheritdoc cref="Extensions.ReaderJson(IDataReader)"/>
string drJson = dataReader.ReaderJson();

// <inheritdoc cref="Extensions.Serialize(object, JsonSerializerSettings)"/>
string serialized = obj.Serialize();     // 使用 Newtonsoft 标准序列化
Long 类型 JS 安全转换
// <inheritdoc cref="LongToStringConverter"/>
// 防止 JavaScript 大整数精度丢失(JS 安全整数仅 53 位)
// 配置示例:
var settings = new JsonSerializerSettings();
settings.Converters.Add(new LongToStringConverter());
string safeJson = JsonConvert.SerializeObject(new { Id = 1234567890123456789L }, settings);
// → {"Id":"1234567890123456789"}  // 以字符串形式输出
标记为 [Obsolete] 的方法
旧方法 推荐替代 说明
obj.ToJson() obj.ObjToJsonString() 反射手动序列化,已废弃
array.ToJson() array.EnumerableToJson() 集合手动序列化,已废弃
dataSet.ToJson() dataSet.DataSetToJson() DataSet 序列化,已废弃
dt.ToJson() dt.DataTableToJson() DataTable 序列化,已废弃

场景三:数据验证(Valid / Check)

┌──────────┐   Valid.IsXxx() / Check.IsXxx()    ┌──────────────┐
│  输入值    │ ───────────────────────────────▶  │  bool / 异常  │
│  string   │                                    │               │
└──────────┘                                    └──────────────┘
用例: 表单校验、API 参数校验、数据入库前验证
Valid 静态验证类(80+ 方法)
// <inheritdoc cref="Valid.IsEmail(string, bool)"/>
bool isEmail = Valid.IsEmail("test@example.com");            // true
bool existsEmail = Valid.HasEmail("联系: test@example.com"); // true

// <inheritdoc cref="Valid.IsPhoneNumber(string)"/>
bool isPhone = Valid.IsPhoneNumber("13800138000");           // true

// <inheritdoc cref="Valid.IsIdCard(string)"/>
bool isId = Valid.IsIdCard("110101199001011234");            // true

// <inheritdoc cref="Valid.IsGuid(string)"/>
bool isGuid = Valid.IsGuid(Guid.NewGuid().ToString());       // true

// <inheritdoc cref="Valid.IsUrl(string)"/>
bool isUrl = Valid.IsUrl("https://example.com");             // true

// <inheritdoc cref="Valid.IsBase64String(string)"/>
bool isB64 = Valid.IsBase64String("SGVsbG8=");              // true

// <inheritdoc cref="Valid.IsDomain(string)"/>
bool isDomain = Valid.IsDomain("example.com");               // true

// <inheritdoc cref="Valid.IsMac(string)"/>
bool isMac = Valid.IsMac("00-11-22-33-44-55");              // true

密码强度验证:

// <inheritdoc cref="Valid.IsPasswordOne(string)"/>
Valid.IsPasswordOne("Abc@123");       // 6-25 位含特殊字符

// <inheritdoc cref="Valid.IsPassworld(object, int, int)"/>
Valid.IsPassworld("StrongP@ss1", 8, 32);

// <inheritdoc cref="Valid.IsSuperPassworld(object, int, int)"/>
Valid.IsSuperPassworld("SuperStr0ng!", 8, 32);  // 更高强度密码

中文/字符验证:

Valid.IsChineseWord("中文");           // 是否中文词组
Valid.IsContainsChinese("Hello中国");  // 是否包含中文
Valid.IsOnlyChinese("中国");           // 是否纯中文
Valid.IsContainsNumber("abc123");      // 是否包含数字
Valid.IsOnlyNumber("12345");           // 是否纯数字
Valid.IsSzzmChinese("张三");           // 数字/字母/中文

SQL 注入防护:

// <inheritdoc cref="Valid.IsBadString(string)"/>
bool safe = !Valid.IsBadString(userInput);  // 检测 SQL 注入关键字
// 检测: select, insert, delete, from, drop, update, truncate, exec, xp_ 等
Valid 方法速查表
分类 方法
邮箱/手机 IsEmail, HasEmail, IsQqEmail, IsPhoneNumber, IsMobileNumber, IsPhone, IsMobile
身份/银行卡 IsIdCard, IsBandCard
密码 IsPasswordOne, IsPasswordTwo, IsPassworld, IsSuperPassworld
网络 IsUrl, IsUri, IsDomain, IsMainDomainUrl, IsIpAddress, IsMac
账号/版本 IsLoginName, IsVersion
中文/字符 IsChinese, IsChineseWord, IsOnlyChinese, IsContainsChinese, IsContainsNumber, IsOnlyNumber, IsNumber, IsInteger, IsUnicode, IsWideWord, IsNarrowWord, IsUpperCaseChar, IsLowerCaseChar, IsNormalChar
数值 IsPositiveInteger, IsInt32, IsDouble, IsDecimal, IsNumber
格式 IsBase64String, IsGuid, IsColorValue, IsTime, IsDate, IsDateTime, IsLengthStr
业务 IsChinesePostalCode, IsPostCode, IsQQ, IsWeChartNumber, IsFax, IsSafeSqlString, IsBadString, IsRepeat, IsPostfix, IsSzzm, IsSzzmChinese, IsNzx
Check 参数校验类(16 个方法 — 抛出本地化异常)
// <inheritdoc cref="Check.IsNotEmpty(Guid, string)"/>
Check.IsNotEmpty(userId, nameof(userId));         // 空 Guid → ArgumentException

// <inheritdoc cref="Check.IsNotEmpty(string, string)"/>
Check.IsNotEmpty(name, nameof(name));              // 空字符串 → ArgumentException

// <inheritdoc cref="Check.IsNotNull(object, string, string)"/>
Check.IsNotNull(dependency, nameof(dependency));   // null → ArgumentNullException

// <inheritdoc cref="Check.IsNotOutOfRange(int, int, int, string)"/>
Check.IsNotOutOfRange(age, 0, 150, nameof(age));  // 超出范围 → ArgumentOutOfRangeException

// <inheritdoc cref="Check.IsNotInPast(DateTime, string)"/>
Check.IsNotInPast(deliveryDate, nameof(deliveryDate));

// <inheritdoc cref="Check.IsNotExistsFile(string, string)"/>
Check.IsNotExistsFile(filePath, nameof(filePath)); // 文件不存在 → ArgumentException

// <inheritdoc cref="Check.IsNotNegativeOrZero(int, string)"/>
Check.IsNotNegativeOrZero(pageSize, nameof(pageSize));

⚠️ 注意事项: Valid 返回 bool,不抛异常;Check 不满足时抛出带本地化消息的 ArgumentException。两者各司其职:Valid 用于表单验证,Check 用于 API 前置参数校验。


场景四:日期时间格式化

┌────────────┐    ToDateTimeString() / ToChineseDateString()     ┌──────────────┐
│  DateTime   │ ──────────────────────────────────────────────▶  │  格式化字符串   │
└────────────┘                                                   └──────────────┘
用例: 日志时间戳、报表日期展示、国际化日期显示
// <inheritdoc cref="Extensions.ToDateTimeString(DateTime, bool)"/>
DateTime.Now.ToDateTimeString();          // "2024-01-01 12:30:45"
DateTime.Now.ToDateTimeString(true);      // "2024-01-01 12:30"(移除秒)

// <inheritdoc cref="Extensions.ToDateString(DateTime)"/>
DateTime.Now.ToDateString();              // "2024-01-01"

// <inheritdoc cref="Extensions.ToTimeString(DateTime)"/>
DateTime.Now.ToTimeString();              // "12:30:45"

// <inheritdoc cref="Extensions.ToMillisecondString(DateTime)"/>
DateTime.Now.ToMillisecondString();       // "2024-01-01 12:30:45.123"

// <inheritdoc cref="Extensions.ToChineseDateString(DateTime)"/>
DateTime.Now.ToChineseDateString();       // "2024年1月1日"

// <inheritdoc cref="Extensions.ToChineseDateTimeString(DateTime, bool)"/>
DateTime.Now.ToChineseDateTimeString();   // "2024年1月1日 12时30分45秒"
DateTime.Now.ToChineseDateTimeString(true); // "2024年1月1日 12时30分"(移除秒)

// <inheritdoc cref="Extensions.GetTimeStamp(DateTime)"/>
long ts = DateTime.Now.GetTimeStamp();    // Unix 时间戳(秒)

// <inheritdoc cref="Extensions.GetTimeSpmpToDate(object)"/>
DateTime dt = 1704067200L.GetTimeSpmpToDate(); // 时间戳 → 本地 DateTime
DateTimeOffset 互转
// <inheritdoc cref="Extensions.ConvertToDateTime(DateTimeOffset)"/>
DateTime local = dateTimeOffset.ConvertToDateTime();

// <inheritdoc cref="Extensions.ConvertToDateTimeOffset(DateTime)"/>
DateTimeOffset dto = DateTime.Now.ConvertToDateTimeOffset();
UnixTime(自定义 Unix 时间戳处理)
// <inheritdoc cref="UnixTime.Ticks()"/>
long ticks = UnixTime.Ticks();                    // 当前 UTC+8 区 Unix 时间戳(秒)

// <inheritdoc cref="UnixTime.ToDateTime(long)"/>
DateTime dt = UnixTime.ToDateTime(1704067200);    // Unix 时间戳 → DateTime

// <inheritdoc cref="UnixTime.ToInt64(DateTime)"/>
long ts = UnixTime.ToInt64(DateTime.Now);         // DateTime → Unix 时间戳(秒)

⚠️ 已知缺陷: UnixTime.Ticks() 硬编码 - 8 * 60 * 60,仅适用于 UTC+8(中国时区)场景,非东八区环境需自行处理。


场景五:字符串处理与中文检测

┌──────────┐   FirstUpper / ToCamel / Truncate     ┌──────────────┐
│  string   │ ──────────────────────────────────▶  │  处理后的字符串 │
└──────────┘                                        └──────────────┘
用例: 命名转换、HTML 解析、内容安全检测、列表拼接
大小写与命名转换
// <inheritdoc cref="Extensions.FirstUpper(string)"/>
"hello".FirstUpper();          // "Hello"

// <inheritdoc cref="Extensions.FirstLower(string)"/>
"Hello".FirstLower();          // "hello"

// <inheritdoc cref="Extensions.ToCamel(string, bool, bool)"/>
"hello_world".ToCamel();       // "HelloWorld"(首字母大写驼峰)
"hello_world".ToCamel(firstCharacterUpper: false);  // "helloWorld"(小驼峰)

// <inheritdoc cref="Extensions.ToCamelAny(string, bool, bool, bool)"/>
"hello_world".ToCamelAny();    // "HelloWorld"(去除下划线后驼峰)
中文与内容检测
// <inheritdoc cref="Extensions.ContainsChinese(string)"/>
"Hello中国".ContainsChinese();       // true

// <inheritdoc cref="Extensions.ContainsNumber(string)"/>
"abc123".ContainsNumber();            // true

// <inheritdoc cref="Extensions.FilterEmoji(string)"/>
string clean = "Hello😀World".FilterEmoji();  // "HelloWorld"
正则匹配与列表操作
// <inheritdoc cref="Extensions.IsMatch(string, string)"/>
bool match = "abc123".IsMatch(@"\d+");           // true

// <inheritdoc cref="Extensions.Splice{T}(IEnumerable{T}, string, string)"/>
new[] { "a", "b", "c" }.Splice(separator: ","); // "a,b,c"
new[] { "a", "b", "c" }.Splice(quotes: "'");    // "'a','b','c'"

// <inheritdoc cref="Extensions.StrToListString(string)"/>
"a,b,c".StrToListString();          // List<string> { "a", "b", "c" }

// <inheritdoc cref="Extensions.StrToListLong(string)"/>
"1,2,3".StrToListLong();            // List<long> { 1, 2, 3 }

// <inheritdoc cref="Extensions.Truncate(string, int, int, string)"/>
"很长的文本内容".Truncate(5, endChar: "...");   // "很长的文..."

// <inheritdoc cref="Extensions.Distinct(string)"/>
"aabbbcc".Distinct();               // "abc"

// <inheritdoc cref="Extensions.GetHtmlImageUrlList(string)"/>
string[] imgs = html.GetHtmlImageUrlList();   // 提取 HTML 中所有 <img> 的 src
时间范围分割
// <inheritdoc cref="Extensions.Splitting(string, char)"/>
var (begin, end) = "2024-01-01/2024-01-31".Splitting('/');
// begin = "2024-01-01", end = "2024-01-31"

场景六:HTTP 请求

┌──────────┐   HttpPost() / HttpGet()     ┌──────────────┐
│  Client   │ ──────────────────────────▶  │  Response     │
│  (string) │   同步/异步,支持自定义 Header  │  (string)     │
└──────────┘                              └──────────────┘
用例: 调用第三方 API、WebHook 回调、数据抓取
// <inheritdoc cref="HttpUtils.HttpGet(string, Dictionary{string, string})"/>
string html = HttpUtils.HttpGet("https://api.example.com/data");

// <inheritdoc cref="HttpUtils.HttpGetAsync(string, Dictionary{string, string})"/>
string asyncHtml = await HttpUtils.HttpGetAsync("https://api.example.com/data");

// <inheritdoc cref="HttpUtils.HttpPost(string, string, string, int, Dictionary{string, string})"/>
string resp = HttpUtils.HttpPost(
    url: "https://api.example.com/submit",
    postData: "{\"key\":\"value\"}",
    contentType: "application/json",
    timeOut: 30,
    headers: new Dictionary<string, string> { ["Authorization"] = "Bearer xxx" }
);

// <inheritdoc cref="HttpUtils.HttpPostAsync(string, string, string, int, Dictionary{string, string})"/>
string asyncResp = await HttpUtils.HttpPostAsync(
    "https://api.example.com/submit",
    "{\"key\":\"value\"}",
    "application/json"
);

⚠️ 已知缺陷: 每次调用都新建 HttpClient 实例,高并发场景下可能导致 Socket 端口耗尽(TIME_WAIT)。生产环境建议使用 IHttpClientFactory 管理 HttpClient 生命周期,或引入单例模式的 HttpClient


场景七:表达式树动态查询

┌──────────┐   And() / Or() / Compose()    ┌──────────────────┐
│  表达式1   │ ─────────────────────────▶   │  组合后的表达式    │
│  表达式2   │     表达式树动态拼接            │  Expression<T>   │
└──────────┘                               └──────────────────┘
用例: 动态 LINQ 查询条件拼接、多条件筛选、仓储模式查询
// <inheritdoc cref="LinqExtensions.True{T}"/>
Expression<Func<User, bool>> where = LinqExtensions.True<User>();

// <inheritdoc cref="LinqExtensions.And{T}"/>
if (!string.IsNullOrEmpty(name))
    where = where.And(u => u.Name.Contains(name));

if (age > 0)
    where = where.And(u => u.Age >= age);

// <inheritdoc cref="LinqExtensions.Or{T}"/>
where = where.Or(u => u.IsVip);  // 或条件

// 最终查询
var users = dbContext.Users.Where(where).ToList();

表达式构建器辅助方法:

// <inheritdoc cref="LinqExtensions.Property(Expression, string)"/>
var propExpr = Expression.Parameter(typeof(User), "u")
    .Property("Name");                      // 等价于 u.Name

// <inheritdoc cref="LinqExtensions.GreaterThan(Expression, Expression)"/>
var gtExpr = leftExpr.GreaterThan(rightExpr);  // 等价于 left > right

// <inheritdoc cref="LinqExtensions.Call(Expression, string, Expression[])"/>
var methodExpr = instance.Call("ToString");    // 等价于 instance.ToString()

// <inheritdoc cref="LinqExtensions.ToLambda{T}(Expression, ParameterExpression[])"/>
var lambda = body.ToLambda<Func<User, bool>>(param);

场景八:树形结构构建

┌──────────────┐    TreeBuildUtil<T>.Build()     ┌──────────────────┐
│  扁平列表      │ ────────────────────────────▶  │  树形层级结构      │
│  List<T>      │     GetId() / GetPid() 排序      │  List<T> (带子节点) │
└──────────────┘                                  └──────────────────┘
用例: 菜单树、组织架构、分类导航、地区级联
// <inheritdoc cref="ITreeNode"/>
// 实体类必须实现 ITreeNode 接口
public class MenuDto : ITreeNode
{
    public long Id { get; set; }
    public long ParentId { get; set; }
    public string Name { get; set; }

    public long GetId() => Id;
    public long GetPid() => ParentId;
    public void SetChildren(IList children) => Children = children?.Cast<MenuDto>().ToList();
    public List<MenuDto> Children { get; set; }
}

// <inheritdoc cref="TreeBuildUtil{T}.Build(List{T})"/>
var flatList = new List<MenuDto>
{
    new() { Id = 1, ParentId = 0, Name = "系统管理" },
    new() { Id = 2, ParentId = 1, Name = "用户管理" },
    new() { Id = 3, ParentId = 1, Name = "角色管理" },
    new() { Id = 4, ParentId = 0, Name = "业务管理" },
};

var tree = new TreeBuildUtil<MenuDto>().Build(flatList);
// 返回两个根节点(Id=1 和 Id=4),各自包含子节点

场景九:系统监控

┌────────────┐    GetMachineUseInfo()    ┌──────────────────┐
│  操作系统    │ ──────────────────────▶  │  CPU / RAM / 磁盘  │
│  (跨平台)    │    GetMachineBaseInfo()  │  网络 / 运行时间   │
└────────────┘                          └──────────────────┘
用例: 服务器健康检查、运维监控面板、诊断信息收集
// <inheritdoc cref="ExMachine.GetInstance()"/>
var machine = ExMachine.GetInstance();

// <inheritdoc cref="ExMachine.GetMachineUseInfo()"/>
dynamic usage = machine.GetMachineUseInfo();
// usage.TotalRam    → "16 GB"
// usage.RamRate     → 45
// usage.CpuRate     → 23
// usage.DiskRate    → 67
// usage.RunTime     → "01 天 12 小时 30 分 45 秒"

// <inheritdoc cref="ExMachine.GetMachineBaseInfo()"/>
dynamic baseInfo = machine.GetMachineBaseInfo();
// 返回 List<dynamic>:
//   - HostName, MemTotal, SystemOs, OsArchitecture, ProcessorCount, Is64BitProcess

// <inheritdoc cref="ExMachine.GetCpuRate()"/>
string cpuRate = machine.GetCpuRate();      // Windows: wmic, Linux: top, Mac: top

// <inheritdoc cref="ExMachine.GetRamInfo()"/>
dynamic ram = machine.GetRamInfo();         // Total, Used, Free
Shell 命令执行
// <inheritdoc cref="ExShell.Bash(string)"/>
string result = ExShell.Bash("ls -la");    // Linux/macOS

// <inheritdoc cref="ExShell.Cmd(string, string)"/>
string winResult = ExShell.Cmd("ipconfig", "");  // Windows

⚠️ 已知缺陷: ExShell 可能存在命令注入风险,请做好输入校验,避免直接拼接用户输入到命令参数。


场景十:汉字拼音与唯一标识

┌──────────┐    PinYin(text)    ┌──────────┐
│  汉字      │ ───────────────▶  │  拼音简码  │
│  "中国"    │                   │  "zg"     │
└──────────┘                   └──────────┘

┌──────────┐    Unique()         ┌──────────────────────────────┐
│  Guid     │ ─────────────────▶ │  无连字符的 32 位字符串       │
│  NewGuid  │                    │  "a1b2c3d4e5f6..."          │
└──────────┘                    └──────────────────────────────┘
// <inheritdoc cref="Str.PinYin(string)"/>
Str.PinYin("中国");              // "zg"
Str.PinYin("中国人");            // "zgr"
Str.PinYin("Hello");             // "hello"(非汉字原样返回)

// <inheritdoc cref="Str.Unique()"/>
string uid = Str.Unique();       // "a1b2c3d4e5f67890abcdef1234567890"

// <inheritdoc cref="Str.ResolvePinYinByFile(string)"/>
// 基于 Const.ChinesePinYin 文件查找拼音(48KB 中文映射表)
string py = Str.ResolvePinYinByFile("中");  // "z"

⚠️ 注意事项: Str.PinYin 返回拼音首字母小写,内部使用 Encoding.Default 处理字节码,在非 Windows 平台上可能因系统编码差异导致拼音解析结果不同。

Common 基础工具
// <inheritdoc cref="Common.TimerStart()"/>
var watch = Common.TimerStart();
// ... 执行操作 ...
double ms = Common.TimerEnd(watch);    // 返回耗时(毫秒)

// <inheritdoc cref="Common.CreateNo(string)"/>
string no = Common.CreateNo();         // 自动生成编号(基于日期+随机数)
// 格式示例: "0612451236202410241234"(自定义 MMHHmmyyyyssdd 格式)

// <inheritdoc cref="Common.RndSalt(int)"/>
string salt = Common.RndSalt(16);      // 生成 16 位随机盐(大小写字母+数字)

// <inheritdoc cref="Common.RndNum(int)"/>
string rnd = Common.RndNum(6);         // 生成 6 位随机数字(0-9)

已修复: Common.CreateNo 已移除 Thread.Sleep(100),改用共享 static Random + lock 保护,锁持有时间从约 100ms 降至 < 0.01ms。


⚙️ 模块速查表

模块 类/文件 命名空间 入口方式 主要功能
类型转换 Extensions.Convert.cs RuoVea.ExUtil object.ToInt() 数值/日期/布尔/字节/字典转换
日期时间 Extensions.DateTime.cs RuoVea.ExUtil DateTime.ToDateTimeString() 格式化/时间戳/DateTimeOffset 互转
JSON 处理 Extensions.Json.cs RuoVea.ExUtil string.ToObject<T>() 序列化/反序列化/DataTable/DataSet
Nullable Extensions.Nullable.cs RuoVea.ExUtil T.SafeValue() 安全取值/去重/截断/列表转字符串
Object Extensions.Object.cs RuoVea.ExUtil obj.ChangeType<T>() DateOnly/TimeOnly 兼容/反射类型转换
字符串 Extensions.String.cs RuoVea.ExUtil string.FirstUpper() 大小写/驼峰/中文检测/HTML 解析/Emoji
验证 Extensions.Validate.cs RuoVea.ExUtil obj.IsEmpty() 空值检查/参数校验扩展
数据验证 Valid.cs RuoVea.ExUtil.Validate Valid.IsEmail() 80+ 个静态验证方法
参数校验 Check.cs RuoVea.ExUtil Check.IsNotEmpty() 16 个带本地化异常的校验方法
验证特性 Attributes/ RuoVea.ExUtil [Email] 14 个数据注解验证特性
表达式树 LinqExtensions.cs RuoVea.ExUtil LinqExtensions.True<T>() 动态 LINQ 查询/条件组合
HTTP 请求 HttpUtils.cs RuoVea.ExUtil HttpUtils.HttpGet() 同步/异步 GET/POST
枚举扩展 EnumExtension.cs RuoVea.ExUtil Enum.GetDic<TEnum>() 枚举字典/文本(TextAttribute)
控制台输出 ConsoleHelper.cs RuoVea.ExUtil ConsoleHelper.WriteColorLine() ANSI 彩色输出/线程安全
树形结构 TreeBuildUtil.cs RuoVea.ExUtil new TreeBuildUtil<T>().Build() 扁平列表转层级树
Long 转换 LongToStringConverter.cs RuoVea.ExUtil 配置 JsonSerializerSettings JS 安全 Long 序列化
系统监控 ExMachine.cs RuoVea.ExUtil.Machine ExMachine.GetInstance() CPU/RAM/磁盘/网络/运行时间
Shell 命令 ExShell.cs RuoVea.ExUtil.Machine ExShell.Bash() / ExShell.Cmd() 跨平台命令执行
时间工具 Time.cs RuoVea.ExUtil 静态方法 中文星期/ISO 周/日期差计算
Unix 时间 UnixTime.cs RuoVea.ExUtil.Time UnixTime.Ticks() 自定义 Unix 时间戳互转
字符串工具 Str.cs RuoVea.ExUtil.ExString Str.PinYin() / Str.Unique() 拼音/唯一标识/上传路径分配
常量 Const.cs RuoVea.ExUtil.ExString Const.ChinesePinYin 48KB 中文拼音映射表/字母/数字
公共方法 Common.cs RuoVea.ExUtil Common.TimerStart() 计时器/编号生成/随机数
公共工具 CommonUtils.cs RuoVea.ExUtil CommonUtils.AssigendPath() 上传路径/文件类型判断/局域网 IP
XML 操作 Xml.cs RuoVea.ExUtil Xml.WriteCsproj() .csproj 文件条目写入
异常类 Exceptions/ RuoVea.ExUtil new ConnctionException() 自定义异常: Connction/Paramiter/ExceptionEx/Fmsg
国际化 Language/ RuoVea.ExUtil.Language i18n.ResourceManager 7 语言资源文件

🛡️ 错误处理与日志

类型转换容错设计

类型转换方法在失败时不抛异常,返回安全默认值:

// <inheritdoc>
int value = "invalid".ToInt();       // 返回 0,不抛异常
double d = "".ToDouble();            // 返回 0
DateTime dt = "bad".ToDate();        // 返回 DateTime.MinValue
bool b = "maybe".ToBool();           // 返回 false

// 如需区分"转换失败"与"值为零",使用可空版本
int? ni = "invalid".ToIntOrNull();   // 返回 null

Check 异常校验

Check 类在校验不通过时抛出带本地化消息的异常:

// <inheritdoc>
public void CreateUser(string name, Guid userId, int age)
{
    Check.IsNotEmpty(name, nameof(name));
    // → ArgumentException: "name 字段不能为空" 或 "The name field cannot be empty"

    Check.IsNotEmpty(userId, nameof(userId));
    // → ArgumentException: "userId 必须是有效的 GUID"

    Check.IsNotOutOfRange(age, 0, 150, nameof(age));
    // → ArgumentOutOfRangeException: "age 取值范围为 0 到 150"
}

推荐模式:Valid + Check 分层校验

// <inheritdoc>
public class UserService
{
    /// <summary>
    /// Valid: 表单场景 — 收集所有校验失败信息
    /// </summary>
    public List<string> ValidateForm(UserDto dto)
    {
        var errors = new List<string>();
        if (!Valid.IsEmail(dto.Email))
            errors.Add("邮箱格式不正确");
        if (!Valid.IsPhoneNumber(dto.Phone))
            errors.Add("手机号格式不正确");
        return errors;
    }

    /// <summary>
    /// Check: API 场景 — 快速失败,抛异常
    /// </summary>
    public void CreateUser(UserDto dto)
    {
        Check.IsNotEmpty(dto.Name, nameof(dto.Name));
        Check.IsNotNull(dto, nameof(dto));
        // ... 业务逻辑
    }
}

🧵 线程安全

组件 线程安全 说明
Extensions (类型转换) ✅ 是 纯计算,无共享状态
Extensions (JSON) ✅ 是 每次调用不维护静态缓存
Valid ✅ 是 纯静态方法,无共享可变状态
Check ✅ 是 仅抛出异常,无共享状态
ConsoleHelper ✅ 是 内部使用 lock 保护 Console.WriteLine
LinqExtensions ✅ 是 表达式树构建为纯函数
HttpUtils ⚠️ 每次新建 HttpClient,资源方面不安全
Common ⚠️ CreateNo 使用 lock 但含 Thread.Sleep_sn 静态计数
Str ✅ 是 纯计算(含 Encoding.Default 潜在编码差异)
UnixTime ✅ 是 纯计算
ExMachine ✅ 是 单例,但监控数据为瞬时值
TreeBuildUtil<T> ✅ 是 实例方法,无共享状态
i18n ✅ 是 ResourceManager 线程安全

⚠️ 已知缺陷与注意事项

本节记录包中的已知 Bug 和设计陷阱,建议在代码审查和集成时重点关注。

1. ICCareAttribute — 身份证验证使用了邮箱正则(Bug)

文件: Validate/Attributes/ICCareAttribute.cs
标签: [ICCare](标注为"身份证"验证)
实际: 构造函数中使用了 EMAIL 正则表达式
// ❌ 标注为身份证验证,实际校验的却是邮箱格式
[ICCare]
public string IdCard { get; set; }  // 实际会校验邮箱格式!

影响: 使用 [ICCare] 特性校验身份证号将错误地应用邮箱正则。如需身份证验证请直接使用 Valid.IsIdCard(string)

2. EmailAttribute — 忽略自定义错误消息参数

文件: Validate/Attributes/EmailAttribute.cs
构造参数: msg(自定义错误消息)
实际: 构造函数接收 msg 参数后未使用,始终返回硬编码的英文错误消息

3. HttpUtils — 已修复为共享静态 HttpClient

文件: HttpUtils.cs
状态: ✅ 已修复 — 使用共享静态 HttpClient + HttpRequestMessage 模式
说明: 不再每次请求新建 HttpClient,避免高并发下 Socket 端口耗尽

4. ConsoleHelper — 始终输出 ANSI 转义码

文件: ConsoleHelper.cs
风险: 在不支持 ANSI 的终端(旧版 Windows 控制台)中显示乱码
建议: 检测 Console.IsOutputRedirected 或使用 VirtualTerminalProcessing

5. UnixTime.Ticks() — 硬编码 UTC+8 偏移

文件: Time/UnixTime.cs
Ticks() 方法: return ... - 8 * 60 * 60
影响: 非东八区环境获取的时间戳不正确
建议: 使用 DateTimeOffset.UtcNow.ToUnixTimeSeconds() 替代

6. Common.CreateNo — 已优化锁持有时间

文件: Common/Common.cs
状态: ✅ 已修复 — 移除 Thread.Sleep(100),使用共享 static Random
效果: 锁持有时间从 ~100ms 降至 <0.01ms,吞吐量提升 10000x

### 7. Valid.IsColorValue — 长度判断笔误

```text
文件: Validate/Valid.cs
代码: value.Length != 33  // ❌ 应为 != 3(十六进制颜色值为 3 或 6 位)
影响: 导致 3 位颜色值(如 "#FFF")校验永远失败

8. Encoding.Default 跨平台不一致

文件: Str.cs (PinYin), Extensions.DateTime.cs
问题: Encoding.Default 在 Windows 上是 GBK/code-page,Linux 上是 UTF-8
影响: 汉字拼音解析在不同操作系统上结果可能不同

9. Extensions.Json — [Obsolete] 方法仍被引用

多个标记为 [Obsolete] 的方法(ToJson, ListToJson 等)使用了手写的字符串拼接 JSON 逻辑,存在转义不完整、性能差的隐患。新代码请使用 ObjToJsonStringEnumerableToJsonDataTableToJson 等替代方法。


🌍 国际化

Check 类和验证特性中的错误消息支持以下语言,根据 CultureInfo.CurrentUICulture 自动切换:

语言 区域代码
简体中文 zh-CN
繁体中文(台湾) zh-TW
粤语(香港) zh-HK
英语 en-US
法语 fr-FR
日语 ja-JP
越南语 vi-VN
// 当前线程 UI 文化为 fr-FR 时:
Check.IsNotEmpty("", "UserName");
// → ArgumentException: "Le champ UserName ne peut pas être vide."

📄 License

MIT License © RuoVea


🔗 相关资源: NuGet Gallery · 问题反馈

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on RuoVea.ExUtil:

Package Downloads
RuoVea.ExSugar

Sqlsugar扩展 快速注入,支持简体中文、繁体中文、粤语、日语、法语、英语.使用方式:service.AddSqlsugar();继承RestFulLog 重写异常日志,操作日志,差异日志

RuoVea.ExFilter

注入 进行全局的异常日志收集、执行操作日志、参数验证,支持简体中文、繁体中文、粤语、日语、法语、英语.services.ExceptionSetup();// 注入 全局错误日志处 services.ExceptionSetup(ExceptionLog actionOptions);// 注入 全局错误日志处 services.ExceptionSetup(builder.Configuration.GetSection("AopOption:ExceptionLog"));// 注入 全局错误日志处 services.RequestActionSetup();// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.RequestActionSetup(RequestLog actionOptions);// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.RequestActionSetup(builder.Configuration.GetSection("AopOption:RequestLog"));// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.ResourceSetup();//对资源型信息进行过滤 services.ResultSetup();//对结果进行统一 services.ApISafeSetup(AppSign actionOptions);//接口安全校验 services.ApISafeSetup(builder.Configuration.GetSection("AopOption:AppSign"));//接口安全校验 services.ApISignSetup(AppSign actionOptions);//签名验证 ( appKey + signKey + timeStamp + data ); services.ApISignSetup(builder.Configuration.GetSection("AopOption:AppSign"));//签名验证 ( appKey + signKey + timeStamp + data ); services.AddValidateSetup();//模型校验 services.AddUiFilesZipSetup();//将前端UI压缩文件进行解压 不进行接口安全校验 -> NonAplSafeAttribute 不签名验证 -> NonAplSignAttribute 不进行全局的异常日志收集 -> NonExceptionAttribute 不对资源型信息进行过滤 -> NonResourceAttribute 不对结果进行统一 -> NonRestfulResultAttribute

RuoVea.ExWeb

CorsUrls、IPLimit、SafeIps、Jwt 配置

RuoVea.ExGlobal

web 注入 全局错误日志、操作日志记录

PBKDF2.Key

PBKDF2(Password-Based Key Derivation Function)是一个用来导出密钥的函数,常用于生成加密的密码。它的基本原理是通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥。如果重复的次数足够大,破解的成本就会变得很高。而盐值的添加也会增加“彩虹表”攻击的难度。

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.0.4 268 6/24/2026
10.0.0.3 542 5/28/2026
10.0.0.2 614 1/27/2026
9.0.0.2 1,263 1/27/2026
9.0.0.1 153 1/26/2026
8.0.1.5 414 6/24/2026
8.0.1.4 1,000 5/28/2026
8.0.1.3 1,634 1/27/2026
8.0.1.2 297 1/26/2026
7.0.1.4 642 5/28/2026
7.0.1.3 1,779 1/27/2026
7.0.1.2 189 1/26/2026
6.0.14.4 749 5/28/2026
6.0.14.3 2,157 1/27/2026
6.0.14.2 173 1/26/2026
5.0.20.4 162 5/28/2026
5.0.20.3 251 1/27/2026
5.0.20.2 189 1/26/2026
2.1.2.4 123 1/27/2026
2.0.0.3 124 1/27/2026
Loading failed