【问题标题】:Deserialising generic type fails to set property of type T反序列化泛型类型无法设置类型 T 的属性
【发布时间】:2019-08-22 20:09:22
【问题描述】:

我在使用 Json.Net 将 JSON 字符串反序列化为泛型类型时遇到了一些问题。

我遇到的问题是泛型类的属性被正确反序列化,在这种情况下,下面的SomeStrings 属性将按预期填充,但Data 属性保留null

我希望有人能阐明我缺少什么,因为序列化相同类型的工作正常。

请看下面的类结构:

public class Foo
{
    public List<string> SomeStrings { get; protected set; } = new List<string>();

    protected Foo()
    {

    }
}

public class GenericFoo<TBar> : Foo
{
    public TBar Data { get; private set; }

    private GenericFoo() {}

    public GenericFoo(TBar data)
    {
        Data = data;
    }

    public GenericFoo(TBar data, params string[] someStrings) :this(data)
    {
        SomeStrings = someStrings.ToList();
    }

}

public class DataClass
{
    public int Id { get; set; }
}

我正在运行的代码:

var settings = new JsonSerializerSettings()
{
    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};

var response = new GenericFoo<DataClass>(new DataClass()
{
    Id = 10
}, "Test");

//serialises completely fine
var json = JsonConvert.SerializeObject(response, settings); 

//Produces JSON: {"Data":{"Id":10},"SomeStrings":["Test"]}

//all properties deserialised fine, Data left null
var obj = JsonConvert.DeserializeObject<GenericFoo<DataClass>>(json, settings); 

【问题讨论】:

  • 你的课堂上没有无参数构造器吗?试着把private 变成一个public
  • @VidmantasBlazevicius - 在序列化器设置中使用ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor 允许私有无参数构造函数。
  • @cmpbedes 检查我的provided answer

标签: c# json.net


【解决方案1】:

通过将[JsonConstructor] 属性应用于构造函数

使用JsonConstructorAttribute 指定在反序列化期间应使用构造函数来创建类。

public class GenericFoo<TBar> : Foo {
    public TBar Data { get; private set; }

    private GenericFoo() { }

    public GenericFoo(TBar data) {
        Data = data;
    }

    [JsonConstructor]
    public GenericFoo(TBar data, params string[] someStrings) : this(data) {
        SomeStrings = someStrings.ToList();
    }

}

反序列化时我得到了所需的行为。即使没有设置

public class Program
{
    public static void Main()
    {
        var response = new GenericFoo<DataClass>(new DataClass()
        {Id = 10}, "Test");
        //serialises completely fine
        var json = JsonConvert.SerializeObject(response);

        var obj = JsonConvert.DeserializeObject<GenericFoo<DataClass>>(json);
        Console.WriteLine(obj.Data.Id); // Prints 10
    }
}

.Net Fiddle of running code.

【讨论】:

    【解决方案2】:

    要反序列化您的 SomeString,只需像这样使用 JsonProperty

     [JsonProperty]
     public List<string> SomeStrings { get; protected set; }
    

    这不适用于带有私有 setter 的公共通用属性。不过,它适用于私有或受保护的通用属性。 (也许是一个错误?)

     [JsonProperty]
     private TBar Data { get; set; }
    

    这可以通过使用隐藏属性进行序列化来解决,如下所示:

    [JsonIgnore]
    public TBar Data { get; private set; }
    
    [JsonProperty(PropertyName = nameof(Data))]
    private TBar PrivateData
    {
        get => Data;
        set => Data = value;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-18
      相关资源
      最近更新 更多