Converter是专为集合批量转换设计的泛型委托,用于List.ConvertAll/Array.ConvertAll等场景,不适用于单值转换或JSON解析;需配合int.TryParse等安全方法使用,且不可用Func替代。

Converter
Converter 的真实使用场景
它最常出现在 List<t>.ConvertAll</t> 和 Array.ConvertAll 中,用于把整个集合的元素一次性转成另一种类型。比如把 List<string></string> 全部转成 List<int></int>,或者把 string[] 映射为 DateTime[]。
它不是为单个值转换设计的——虽然语法上能调用 converter("123"),但这样用既没优势,也违背设计意图。
- 必须是泛型委托,类型参数在编译期固定,不支持运行时动态决定目标类型
- 不处理异常:如果某个元素转换失败(如
"abc"转int),整个ConvertAll会直接抛FormatException - 无法传入额外上下文(比如文化信息、配置选项),所有逻辑必须封装在委托方法体内
正确写法:配合 ConvertAll 使用
下面这段代码才是典型、安全、可读的用法:
List<string> strings = new List<string> { "1", "2", "3" };
Converter<string, int> stringToInt = s => int.Parse(s);
List<int> numbers = strings.ConvertAll(stringToInt);
注意三点:
- 委托变量名(
stringToInt)建议体现输入输出语义,方便后期维护 - lambda 内尽量用
int.TryParse替代int.Parse,否则一个坏数据就崩掉整批转换 - 不要在 lambda 里写复杂逻辑(如 IO、锁、数据库调用),
ConvertAll是同步且无并发保护的
和 Func 的关键区别
Converter<string, int> 和 Func<string, int> 看似等价,但它们语义不同:
-
Converter是 .NET Framework 2.0 就存在的老类型,专为集合转换 API 设计,被ConvertAll等方法强依赖 -
Func更通用,可用于 LINQ、事件、DI 注入等任意需要函数式抽象的地方 - 二者不能互相赋值(即使签名相同),因为类型系统不认为它们兼容:
Func<string, int> f = converter;编译报错
所以别试图用 Func 替换 Converter 去调 ConvertAll——它只认 Converter。
容易忽略的性能与兼容性点
在 .NET Core / .NET 5+ 中,ConvertAll 内部仍是基于数组分配和逐项调用,没有自动并行化。如果你要转换百万级数据:
- 考虑用
AsParallel().Select(...).ToList(),但要注意线程安全(比如委托里用了静态变量) - 避免在
Converter中触发装箱(如把int转object),尤其在值类型频繁转换时影响 GC - Unity IL2CPP 构建下,
Converter的泛型实例可能被裁剪,需在link.xml中保留System.Converter`2
真正难处理的从来不是怎么写这行代码,而是当 ConvertAll 在生产环境突然抛出 NullReferenceException 时,你得立刻意识到:源头集合里混进了 null,而你的 Converter 没做空检查。


















