ToString()重写必须用override关键字,签名严格匹配public override string ToString(),返回安全格式化字符串且无副作用。

ToString() 重写必须加 override 关键字
不加 override 就是隐藏基类方法,不是重写——调用时看变量声明类型,不是实际类型,结果完全不符合预期。比如 object o = new Person(); Console.WriteLine(o.ToString());,如果没用 override,还是输出 Namespace.Person。
- 必须从
System.Object继承(所有类默认满足),且方法签名严格匹配:public override string ToString() - 不能写成
public new string ToString(),那是new隐藏,多态失效 - 返回值必须是
string,不能是void或其他类型,否则编译不过
格式化逻辑别硬拼字符串,优先用插值或 String.Format
直接 "Name: " + Name + ", Age: " + Age 看似简单,但空值、特殊字符、本地化需求一来就崩。插值表达式更安全可读,也方便后续加格式控制。
- 推荐写法:
return $"{{Name ?? "未知"}} ({{Age:D2}})";,??防NullReferenceException,D2保证两位数字 - 避免在
ToString()里做耗时操作(如 IO、网络请求、复杂计算),它可能被日志、调试器高频调用 - 如果需要多种格式(如简略/详细),不要靠参数重载——
ToString()签名固定;改用自定义方法,如ToShortString()或ToString(string format)(需实现IFormattable)
调试器显示和日志输出依赖 ToString(),但别把它当业务逻辑入口
Visual Studio 调试窗口、Console.WriteLine、NLog/Serilog 默认序列化都直接调 ToString()。很多人在这里塞了 Console.WriteLine 或修改状态,结果调试时程序行为异常。
- ToString() 必须是纯函数:无副作用、不修改字段、不抛异常(除非严重内部错误)、线程安全
- 如果对象包含敏感字段(如密码、token),
ToString()里要主动脱敏,而不是暴露原始值 - 集合类(如
List)的默认ToString()只返回类型名,不是元素内容——这是常见困惑点,不是 bug
继承链中 ToString() 的调用容易漏掉 base.ToString()
子类重写时,如果想保留父类已有逻辑(比如基类已格式化了 ID 和创建时间),又想追加自己的字段,不调 base.ToString() 就丢了那部分。
- 典型错误:
return $"{{Status}}";—— 完全覆盖,父类信息全丢 - 合理做法:
return $"{base.ToString()}, Status: {{Status}}";,前提是父类ToString()返回有意义的字符串 - 如果父类是第三方或
sealed,无法控制其ToString()内容,那就老老实实自己组织全部字段,别假设“它会返回啥”
最麻烦的其实是嵌套对象:某个属性本身也重写了 ToString(),但你忘了它可能返回 null 或格式混乱,导致外层拼接崩溃。每次用前加个空值判断,比事后查 NullReference 强得多。











