为什么嵌套字典的反序列化在C#中抛出异常,但在F#中有效



我用Newtonsoft.Json.FSharp.将F#记录类型序列化到Json

type Prices =  Dictionary<string, decimal>
type PriceList = {Id:string; Name:string; Date:DateTime; CurrencySymbol:string; Status:Status; Prices:Prices}
let private converters : JsonConverter array =
  [| BigIntConverter();
    GuidConverter();
    ListConverter();
    OptionConverter();
    MapConverter();
    TupleArrayConverter();
    UnionConverter();
    UriConverter();
    CultureInfoConverter() |]
let private settings = JsonSerializerSettings (
                        Converters = converters,
                        Formatting = Formatting.Indented,
                        NullValueHandling = NullValueHandling.Ignore)
let serialize obj = JsonConvert.SerializeObject(obj, settings)

JSON中的结果是:

{
  "Id": "PriceList20140201",
  "Name": "PriceList",
  "Date": "2014-02-01T00:00:00+01:00",
  "CurrencySymbol": "€",
  "Status": 0,
  "Prices": {
    "ItemCodeA": 512.4,
    "ItemCodeB": 471.0
  }
}

如果我将其反序列化,它会很好地工作

JsonConvert.DeserializeObject<PriceList>(text)

F#交互中的结果:

val y : PriceList =
{Id = "PriceList20140201";
Name = "PriceList";
Date = 01.04.2014 00:00:00;
CurrencySymbol = "€";
Status = Sale;
Prices =
 dict
   [("ItemCodeA", 512.4M); ("ItemCodeB", 471.0M);...];}

现在我想使用Newtonsoft.Json 在C#中反序列化它

public class PriceList
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public string CurrencySymbol { get; set; }
    public Status Status { get; set; }
    public Prices Prices { get; set; }
}
public class Prices : Dictionary<string, decimal>
{
}
...
JsonConvert.DeserializeObject<PriceList>(json)

这导致JsonSerializationException:

无法将当前JSON数组(例如[1,2,3])反序列化为类型'Halep.Logic.OfferManagement.合同.数据类.定价.价格'因为该类型需要一个JSON对象(例如{"name":"value"})正确反序列化。要修复此错误,请将JSON更改为JSON对象(例如{"name":"value"})或将反序列化的类型更改为数组或实现集合接口的类型(例如。ICollection,IList)类似列表,可以从JSON反序列化大堆JsonArrayAttribute也可以添加到类型中,以强制它从JSON数组反序列化。路径"价格",第7行,位置13。

我读到我需要一个用于嵌套词典的CustomConverter。但据我所知,从6.0版本开始应该是可能的。?没有自定义转换器。我目前使用的是8.0.3。为什么它在F#中有效,而在C#中无效?C#对象结构错误吗?

我试图用Dictionary直接替换PriceList,但结果相同。

更新最后一句话的意思是我试过这个:

public class PriceList
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public string CurrencySymbol { get; set; }
    public Status Status { get; set; }
    public Dictionary<string, decimal> Prices { get; set; }
}

得到了几乎相同的例外:

无法将当前JSON数组(例如[1,2,3])反序列化为类型'System.Collections.Generic.Dictionary `2[System.String,System.Decimal]'因为该类型需要一个JSON对象(例如{"name":"value"})正确反序列化。要修复此错误,请将JSON更改为JSON对象(例如{"name":"value"})或将反序列化的类型更改为数组或实现集合接口的类型(例如。ICollection,IList)类似列表,可以从JSON反序列化大堆JsonArrayAttribute也可以添加到类型中,以强制它从JSON数组反序列化。路径"价格",第7行,位置13。

更新2:解决方案此代码有效。@JustinNiesner的最后一条评论给出了解决方案。问题是,输入实际上是这样的,它包含[]而不是{}:

{
  "Id": "PriceList20140201",
  "Name": "PriceList",
  "Date": "2014-02-01T00:00:00+01:00",
  "CurrencySymbol": "€",
  "Status": 0,
  "Prices": [
    "ItemCodeA": 512.4,
    "ItemCodeB": 471.0
  ]

}

type Prices = Dictionary<string, decimal>是F#中的一个类型缩写,而不是像C#代码那样创建一个从Dictionary<string, decimal>继承的新类:

F#型缩写

这就是为什么您会看到两者之间的反序列化差异。

有两种方法可以在C#中解决这个问题。第一种方法是使用using指令创建类似类型的别名:

using Prices = System.Collections.Generic.Dictionary<string, object>;

另一种方法是简单地将PriceList类定义中的类型替换为Decimal<string, decimal>

public class PriceList
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public string CurrencySymbol { get; set; }
    public Status Status { get; set; }
    public Dictionary<string, decimal> Prices { get; set; }
}

然后C#反序列化将以与F#相同的方式工作。

相关内容

最新更新