ValueConverter 类型转换工具
ValueConverter 提供统一的类型转换接口,使用注册表模式管理转换器,支持内置和自定义转换器。
using MiCake.Util.Convert;Convert 方法
Section titled “Convert 方法”// 字符串转整数int intValue = ValueConverter.Convert<string, int>("123");
// 字符串转日期DateTime dateValue = ValueConverter.Convert<string, DateTime>("2024-01-01");
// Guid 转换Guid guid = ValueConverter.Convert<string, Guid>("550e8400-e29b-41d4-a716-446655440000");
// Version 转换Version? version = ValueConverter.Convert<string, Version>("1.2.3");Convert 方法行为
Section titled “Convert 方法行为”- null 值处理: 源值为 null 时会抛出
ArgumentNullException - 转换失败: 失败时返回目标类型的默认值(如
0、null、Guid.Empty)而不抛出异常 - 转换顺序:
- 查询注册表中的自定义转换器(按注册顺序)
- 使用内置的
SystemValueConverter作为后备
自定义转换器
Section titled “自定义转换器”public class MoneyConverter : IValueConverter<string, Money>{ public bool CanConvert(string value) { return !string.IsNullOrEmpty(value) && value.Contains(' '); }
public Money? Convert(string value) { var parts = value.Split(' '); if (parts.Length != 2) return null;
if (!decimal.TryParse(parts[0], out var amount)) return null;
return new Money(amount, parts[1]); }}// 使用工厂方法注册ValueConverter.RegisterConverter(() => new MoneyConverter());
// 使用实例注册ValueConverter.RegisterConverter(new MoneyConverter());
// 泛型注册ValueConverter.RegisterConverter<string, Money>(() => new MoneyConverter());使用自定义转换器
Section titled “使用自定义转换器”// 注册后直接使用var money = ValueConverter.Convert<string, Money>("99.99 USD");Console.WriteLine($"{money.Amount} {money.Currency}"); // 99.99 USDHasConverter - 检查转换器
Section titled “HasConverter - 检查转换器”if (ValueConverter.HasConverter<string, Money>()){ Console.WriteLine("转换器已注册");}ClearConverters - 清除指定转换器
Section titled “ClearConverters - 清除指定转换器”// 清除 string 到 Money 的所有转换器ValueConverter.ClearConverters<string, Money>();ClearAll - 清空所有转换器
Section titled “ClearAll - 清空所有转换器”// 清空所有自定义转换器(内置转换器也会被清除)ValueConverter.ClearAll();SetRegistry - 设置自定义注册表
Section titled “SetRegistry - 设置自定义注册表”// 创建自定义注册表var customRegistry = new DefaultConverterRegistry();customRegistry.Register<string, MyType>(() => new MyTypeConverter());
// 应用自定义注册表ValueConverter.SetRegistry(customRegistry);ResetRegistry - 重置为默认注册表
Section titled “ResetRegistry - 重置为默认注册表”// 重置为默认注册表并重新注册内置转换器ValueConverter.ResetRegistry();MiCake 预注册了以下内置转换器:
GuidValueConverter
Section titled “GuidValueConverter”// 字符串转 GuidGuid guid1 = ValueConverter.Convert<string, Guid>("550e8400-e29b-41d4-a716-446655440000");
// Guid 转 Guid(直接返回)Guid guid2 = ValueConverter.Convert<Guid, Guid>(guid1);
// 失败时返回 Guid.EmptyGuid empty = ValueConverter.Convert<string, Guid>("invalid"); // Guid.EmptyVersionValueConverter
Section titled “VersionValueConverter”// 字符串转 VersionVersion? version1 = ValueConverter.Convert<string, Version>("1.2.3");Console.WriteLine(version1); // 1.2.3
// Version 转 Version(直接返回)Version? version2 = ValueConverter.Convert<Version, Version>(version1);
// 失败时返回 nullVersion? nullVersion = ValueConverter.Convert<string, Version>("invalid"); // nullSystemValueConverter
Section titled “SystemValueConverter”作为后备转换器,使用 System.Convert.ChangeType:
// 支持大多数基本类型转换int intVal = ValueConverter.Convert<string, int>("42");double doubleVal = ValueConverter.Convert<string, double>("3.14");bool boolVal = ValueConverter.Convert<string, bool>("true");DateTime dateVal = ValueConverter.Convert<string, DateTime>("2024-01-01");注册表与线程安全
Section titled “注册表与线程安全”DefaultConverterRegistry 使用锁保护读写操作,确保线程安全:
// 多线程环境下安全注册Parallel.For(0, 100, i =>{ ValueConverter.RegisterConverter<string, int>(() => new MyIntConverter());});复杂类型转换
Section titled “复杂类型转换”public class ProductDto{ public string Id { get; set; } public string Price { get; set; } public string Category { get; set; }}
// 注册转换器ValueConverter.RegisterConverter<string, int>(() => new StringToIntConverter());ValueConverter.RegisterConverter<string, decimal>(() => new StringToDecimalConverter());
// 使用var dto = new ProductDto{ Id = "123", Price = "99.99", Category = "1"};
int id = ValueConverter.Convert<string, int>(dto.Id);decimal price = ValueConverter.Convert<string, decimal>(dto.Price);int categoryId = ValueConverter.Convert<string, int>(dto.Category);在服务中使用
Section titled “在服务中使用”public class DataImportService : IScopedService{ public Product ParseProduct(Dictionary<string, string> data) { return new Product { Id = ValueConverter.Convert<string, int>(data["Id"]), Name = data["Name"], Price = ValueConverter.Convert<string, decimal>(data["Price"]), CreatedAt = ValueConverter.Convert<string, DateTime>(data["CreatedAt"]) }; }}// 注册多个转换器实现链式转换ValueConverter.RegisterConverter<string, Guid>(() => new StringToGuidConverter());ValueConverter.RegisterConverter<Guid, int>(() => new GuidToIntConverter());
// 分步转换string guidString = "550e8400-e29b-41d4-a716-446655440000";Guid guid = ValueConverter.Convert<string, Guid>(guidString);int hashCode = ValueConverter.Convert<Guid, int>(guid);1. 注册特定转换器
Section titled “1. 注册特定转换器”// ✅ 正确:注册专用转换器覆盖默认行为ValueConverter.RegisterConverter<string, Money>(() => new MoneyConverter());
// ❌ 不推荐:依赖 SystemValueConverter 处理复杂类型var money = ValueConverter.Convert<string, Money>("99.99 USD"); // 可能失败2. 处理转换失败
Section titled “2. 处理转换失败”// ✅ 正确:检查返回值int? value = ValueConverter.Convert<string, int?>("invalid");if (value == null){ Console.WriteLine("转换失败");}
// ⚠️ 注意:非可空类型返回默认值int defaultValue = ValueConverter.Convert<string, int>("invalid"); // 返回 03. 线程安全注册
Section titled “3. 线程安全注册”// ✅ 正确:在应用启动时注册public class MyModule : MiCakeModule{ public override void ConfigureServices(ModuleConfigServiceContext context) { ValueConverter.RegisterConverter<string, Money>(() => new MoneyConverter()); base.ConfigureServices(context); }}
// ❌ 不推荐:在运行时频繁注册/清除ValueConverter.RegisterConverter<string, int>(() => new MyConverter());ValueConverter.ClearConverters<string, int>();4. 转换器顺序
Section titled “4. 转换器顺序”// ✅ 正确:按优先级注册ValueConverter.RegisterConverter<string, int>(() => new SpecialIntConverter()); // 优先ValueConverter.RegisterConverter<string, int>(() => new GeneralIntConverter()); // 后备
// Convert 会按注册顺序尝试int value = ValueConverter.Convert<string, int>("123"); // 使用 SpecialIntConverter5. 实现幂等转换器
Section titled “5. 实现幂等转换器”// ✅ 正确:幂等转换器public class SafeIntConverter : IValueConverter<string, int>{ public bool CanConvert(string value) { return int.TryParse(value, out _); }
public int? Convert(string value) { return int.TryParse(value, out var result) ? result : null; }}
// ❌ 错误:非幂等转换器public class CountingConverter : IValueConverter<string, int>{ private int _count = 0;
public int? Convert(string value) { return _count++; // 每次调用返回不同结果 }}管理方法总结
Section titled “管理方法总结”| 方法 | 说明 |
|---|---|
Convert<TSource, TDest>(source) | 转换值,失败返回默认值 |
RegisterConverter<TSource, TDest>(factory) | 注册转换器工厂 |
RegisterConverter(converter) | 注册转换器实例 |
HasConverter<TSource, TDest>() | 检查是否存在转换器 |
ClearConverters<TSource, TDest>() | 清除指定类型的转换器 |
ClearAll() | 清除所有转换器 |
SetRegistry(registry) | 设置自定义注册表 |
ResetRegistry() | 重置为默认注册表 |
- 转换失败返回默认值:
Convert方法不会抛出异常 - null 值抛出异常:源值为 null 时抛出
ArgumentNullException - 转换器顺序:按注册顺序尝试转换器
- 线程安全:
DefaultConverterRegistry支持线程安全操作 - 内置后备:
SystemValueConverter作为最后的后备转换器