如何判断C#类型的ToString()是否返回有效数据字符串?(自定义序列化场景)
这个问题确实戳中了C#里ToString()方法的一个痛点——它的行为完全依赖类型的实现,有的时候能输出清晰的数值或数据表示,有的时候就只返回干巴巴的类型名。想要精准判断该用它的结果还是转Base64,没有绝对完美的银弹,但有几个实用思路可以覆盖大部分场景:
检查是否重写了ToString()
默认的object.ToString()就是返回类型的完全限定名,所以如果一个类型没有重写这个方法,那调用它肯定得不到有效数据。可以通过反射快速判断:bool IsToStringOverridden<T>(T obj) { var method = typeof(T).GetMethod("ToString", Type.EmptyTypes); return method.DeclaringType != typeof(object); }不过要注意:如果子类继承了父类重写的
ToString(),这个判断会认为子类没重写,但实际调用的是父类的自定义实现——这种情况一般不影响,因为父类的实现已经是有意义的了。对比默认实现的结果
要是不确定是否重写,直接调用ToString()后和默认结果对比也是个简单有效的办法:bool HasMeaningfulToString(object obj) { var defaultResult = obj.GetType().ToString(); var actualResult = obj.ToString(); return actualResult != defaultResult; }唯一的小瑕疵是:极少数情况下,有人可能重写了
ToString()但还是返回类型名(虽然这毫无意义),这时候会误判,但这种场景几乎不会遇到。维护白名单覆盖已知类型
对于系统自带的数值类型(int、float、decimal等)、DateTime、Guid这些,它们的ToString()肯定返回有意义的字符串,可以直接把这些类型加入白名单:private static readonly HashSet<Type> MeaningfulToStringTypes = new HashSet<Type> { typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal), typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(uint), typeof(ulong), typeof(DateTime), typeof(Guid), typeof(string) }; bool IsInWhitelist(object obj) { return MeaningfulToStringTypes.Contains(obj.GetType()); }这个方案最稳妥,因为你完全清楚这些类型的
ToString()行为。用自定义属性标记可控类型
如果是你自己开发的类,最可靠的方式是给那些ToString()返回完整有效数据的类型加个自定义属性,序列化时检查这个属性即可:[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class UseToStringForSerialization : Attribute { } // 标记你的类 [UseToStringForSerialization] public class MyDataClass { public int Id { get; set; } public string Name { get; set; } public override string ToString() => $"{Id}|{Name}"; } // 判断逻辑 bool ShouldUseToString(object obj) { return obj.GetType().GetCustomAttribute<UseToStringForSerialization>() != null; }这种方式完全由你掌控规则,不会出现意外的误判。
额外提醒
要注意:就算ToString()返回了有意义的字符串,也不一定适合用来序列化——比如有些类的ToString()只返回部分字段(比如只展示名称不展示ID),用它序列化会丢失数据。所以最好确保那些被你选中用ToString()序列化的类型,其ToString()返回的是完整的、可反序列化的信息(不过一般来说,ToString()更多用于展示,序列化还是建议用专门的序列化框架,这里只是针对你的特定场景)。
内容的提问来源于stack exchange,提问作者Sylvain B.

