【问题标题】:JSON deserialize to constructed protected setter arrayJSON 反序列化为构造的受保护的 setter 数组
【发布时间】:2014-11-15 00:06:19
【问题描述】:

我使用 Newtonsoft JSON 序列化/反序列化我的对象。其中一个包含一个带有受保护的 setter 的数组,因为构造函数自己构建数组并且只操作成员。

这可以毫无问题地序列化,但是在反序列化时,它被忽略了,因为它不是公共的。我尝试了一个自定义转换器,它也没有被调用,因为它不是公开的。

这是一个最小化的例子:

public static class TestCoordsDeserialization
{
    private class Coords
    {
        public Double X { get; set; }
        public Double Y { get; set; }
        public Double Z { get; set; }
        public Double A { get; set; }
    }

    private class Engine
    {
        public string Text { get; set; }
        public int Id { get; set; }
        public Coords[] Outs { get; protected set; }

        public Engine()
        {
            this.Outs = new Coords[3];
            for (int i = 0; i < this.Outs.Length; i++)
            {
                this.Outs[i] = new Coords();
            }
        }
    }

    public static void Test()
    {
        Engine e = new Engine();
        e.Id = 42;
        e.Text = "MyText";
        e.Outs[0] = new Coords() { A = 0, X = 10, Y = 11, Z = 0 };
        e.Outs[1] = new Coords() { A = 0, X = 20, Y = 22, Z = 0 };
        e.Outs[2] = new Coords() { A = 0, X = 30, Y = 33, Z = 0 };
        string json = JsonConvert.SerializeObject(e);
        Console.WriteLine(json); //{"Text":"MyText","Id":42,"Positions":{"Test":9,"Outs":[{"X":10.0,"Y":11.0,"Z":0.0,"A":0.0},{"X":20.0,"Y":22.0,"Z":0.0,"A":0.0},{"X":30.0,"Y":33.0,"Z":0.0,"A":0.0}]}}
        Engine r = JsonConvert.DeserializeObject<Engine>(json);
        double value = r.Outs[1].X; // should be '20.0'
        Console.WriteLine(value);
        Debugger.Break();
    }
}

我怎样才能使value 成为20.0

【问题讨论】:

标签: c# arrays json serialization json.net


【解决方案1】:

使用[JsonProperty] 属性标记Outs

    private class Engine
    {
        public string Text { get; set; }
        public int Id { get; set; }
        [JsonProperty]  // Causes the protected setter to be called on deserialization.
        public Coords[] Outs { get; protected set; }

        public Engine()
        {
            this.Outs = new Coords[3];
            for (int i = 0; i < this.Outs.Length; i++)
            {
                this.Outs[i] = new Coords();
            }
        }
    }

【讨论】:

    【解决方案2】:

    试试这个:

    var contractResolver = new DefaultContractResolver();
    contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;
    Engine r = JsonConvert.DeserializeObject<Engine>(json), new JsonSerializerSettings
                {
                    ContractResolver = contractResolver
                });
    

    使用上述代码,您将收到以下警告消息:

    'DefaultContractResolver.DefaultMembersSearchFlags' 已过时: 'DefaultMembersSearchFlags 已过时。修改成员 序列化继承自 DefaultContractResolver 并覆盖 取而代之的是 GetSerializableMembers 方法。'

    要解决它,您可以改用以下解决方案:

    创建一个继承自DefaultContractResolver 的类以获取非公共属性:

    public class CustomContractResolver : DefaultContractResolver
        {
            protected override JsonProperty CreateProperty(
                MemberInfo member,
                MemberSerialization memberSerialization)
            {
                var prop = base.CreateProperty(member, memberSerialization);
    
                if (!prop.Writable)
                {
                    var property = member as PropertyInfo;
                    if (property != null)
                    {
                        var hasNonPublicSetter = property.GetSetMethod(true) != null;
                        prop.Writable = hasNonPublicSetter;
                    }
                }
    
                return prop;
            }
        }
    

    最后按如下方式使用:

    var contractResolver = new CustomContractResolver();
    Engine r = JsonConvert.DeserializeObject<Engine>(json), new JsonSerializerSettings
                {
                    ContractResolver = contractResolver
                });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-21
      • 2016-02-19
      • 2016-04-07
      • 2017-01-09
      • 2011-05-30
      • 1970-01-01
      • 2016-09-25
      • 2011-05-02
      相关资源
      最近更新 更多