如何反序列化带in参数只读结构体构造函数的只读结构体?
解决Json.NET反序列化带
in参数构造函数的readonly struct异常问题 这个问题我之前也碰到过!根源在于Json.NET(Newtonsoft.Json)的构造函数解析逻辑不支持处理带in/ref/out修饰符的参数。当你给Outer的构造函数用in Inner作为参数时,Json.NET会把这个参数的类型识别为Inner&(值类型的引用包装),而不是原本的Inner结构体类型,所以它找不到对应的构造函数来完成反序列化,就抛出了你看到的那个JsonSerializationException。
下面给两种解决方案,你可以根据自己的需求选择:
方案1:移除构造函数的in修饰符(最简单)
对于readonly struct来说,编译器已经会对传值操作做优化——尤其是小结构体,实际不会产生额外的副本(这也是readonly struct设计的优势之一)。所以直接去掉in修饰符,Json.NET就能正常识别构造函数了:
public readonly struct Outer { [JsonConstructor] public Outer(Inner inner) => Inner = inner; // 移除in修饰符 public Inner Inner { get; } }
修改后重新运行你的代码,反序列化就能正常工作,同时也能保证结构体的不可变性。
方案2:自定义JsonConverter(保留in参数的场景)
如果你因为某些原因必须保留in参数的构造函数(比如你的Inner是非常大的结构体,确实需要避免副本),可以写一个自定义的JsonConverter来手动处理Outer的反序列化逻辑:
首先创建转换器类:
public class OuterConverter : JsonConverter<Outer> { public override Outer ReadJson(JsonReader reader, Type objectType, Outer existingValue, bool hasExistingValue, JsonSerializer serializer) { // 先把JSON反序列化为Inner对象 var inner = serializer.Deserialize<Inner>(reader); // 调用带in参数的构造函数创建Outer实例 return new Outer(in inner); } public override void WriteJson(JsonWriter writer, Outer value, JsonSerializer serializer) { // 序列化逻辑直接复用默认行为即可 serializer.Serialize(writer, new { value.Inner }); } }
然后在反序列化时指定这个转换器:
try { var originalOuter = new Outer(new Inner(1)); var json = JsonConvert.SerializeObject(originalOuter); // 添加转换器设置 var settings = new JsonSerializerSettings(); settings.Converters.Add(new OuterConverter()); var newOuter = JsonConvert.DeserializeObject<Outer>(json, settings); Assert.IsTrue(originalOuter.Inner.I == newOuter.Inner.I); Console.WriteLine(json); } catch (Exception ex) { Console.WriteLine("Failed with unhandled exception: "); Console.WriteLine(ex); throw; }
这样就能绕过Json.NET对in参数的识别问题,手动完成反序列化流程。
内容的提问来源于stack exchange,提问作者Jeremy Morton
相关产品推荐
相关产品推荐

