JsonNet忽略ISerializable,将实现IEnumerable<char>的字符串包装类序列化为数组求助
我太懂你这个烦恼了——明明想把自定义的字符串包装类序列化成普通字符串,结果因为实现了IEnumerable<char>接口,Json.NET直接把它当成字符数组处理,哪怕加了ISerializable接口和[Serializable]特性也完全不管用。这其实是Json.NET的默认机制:它会优先识别实现了IEnumerable的类型,把它们当作集合来序列化,完全跳过你设置的自定义序列化逻辑。
下面给你几个靠谱的解决方法,按推荐程度排序:
方法一:自定义Json转换器(最推荐)
写一个专属的Json转换器,直接告诉Json.NET该怎么序列化你的包装类,绕过它的集合处理逻辑。
假设你的包装类叫StringWrapper,内部持有字符串的核心代码如下:
public class StringWrapper : IEnumerable<char> { private readonly string _innerString; public StringWrapper(string value) { _innerString = value; } // IEnumerable<char>的实现代码... public override string ToString() => _innerString; }
对应的转换器可以这么写:
public class StringWrapperConverter : JsonConverter<StringWrapper> { // 序列化时直接输出字符串 public override void WriteJson(JsonWriter writer, StringWrapper value, JsonSerializer serializer) { writer.WriteValue(value.ToString()); } // 反序列化时把字符串转回包装类实例 public override StringWrapper ReadJson(JsonReader reader, Type objectType, StringWrapper existingValue, bool hasExistingValue, JsonSerializer serializer) { var inputString = reader.Value as string; return inputString != null ? new StringWrapper(inputString) : null; } }
最后在包装类上加上[JsonConverter]特性,指定使用这个转换器:
[JsonConverter(typeof(StringWrapperConverter))] public class StringWrapper : IEnumerable<char> { // 类的其他代码... }
这样Json.NET就会乖乖按照你指定的逻辑,把包装类序列化成纯字符串了。
方法二:用JsonObjectAttribute强制当作对象处理
如果你不想写转换器,可以给类加上[JsonObject]特性,指定只序列化你想要的属性,让Json.NET把它当作普通对象而非集合。
比如给包装类加一个公开的字符串属性,并标记需要序列化:
[JsonObject(MemberSerialization.OptIn)] public class StringWrapper : IEnumerable<char> { private readonly string _innerString; public StringWrapper(string value) { _innerString = value; } [JsonProperty] // 标记该属性需要被序列化 public string InnerValue => _innerString; // IEnumerable<char>的实现代码... }
这种方式序列化后会得到{"InnerValue":"你的字符串内容"}的结构,虽然不是纯字符串,但至少不是数组。如果想要直接输出字符串,还是方法一更合适。
方法三:修改Json.NET全局配置(不推荐)
你可以尝试修改JsonSerializerSettings,让它优先使用ISerializable的逻辑,但这个方法可能影响其他类型的序列化,而且不一定百分百生效——因为Json.NET对集合的处理优先级很高。
示例代码:
var settings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver { IgnoreSerializableInterface = false, IgnoreSerializableAttribute = false } }; // 序列化时使用这个配置 var json = JsonConvert.SerializeObject(yourStringWrapper, settings);
除非你有全局统一的需求,否则不推荐用这个方法,自定义转换器的可靠性和灵活性都更高。
为什么加ISerializable没用?
Json.NET默认有一套优先级规则:当类型实现了IEnumerable时,它会优先触发集合序列化逻辑,完全忽略ISerializable接口和[Serializable]特性的设置。哪怕你开启了IgnoreSerializableInterface = false,集合的处理逻辑还是会覆盖掉ISerializable的逻辑,所以必须用转换器或者强制标记为对象来绕过这个机制。
内容的提问来源于stack exchange,提问作者t3chb0t

