Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#Newtonsoft.Json自定义反序列化程序_C#_Json_Json.net - Fatal编程技术网

C#Newtonsoft.Json自定义反序列化程序

C#Newtonsoft.Json自定义反序列化程序,c#,json,json.net,C#,Json,Json.net,我正在使用一个API,它以一种不同于我所习惯的方式向我返回结果,而且似乎是非标准的 例如,下面是一段客户数据: { “客户ID”:{ “值”:“示例” }, “CustomerCurrencyID”:{ “价值”:“美元” } } 这个“value”属性似乎非常不必要,所以我想看看是否可以将其全部忽略,并将JSON反序列化为如下所示的对象: class客户{ 公共字符串CustomerID{get;set;} 公共字符串CustomerCurrencyID{get;set;} } 我目前正在

我正在使用一个API,它以一种不同于我所习惯的方式向我返回结果,而且似乎是非标准的

例如,下面是一段客户数据:

{
“客户ID”:{
“值”:“示例”
},
“CustomerCurrencyID”:{
“价值”:“美元”
}
}
这个“value”属性似乎非常不必要,所以我想看看是否可以将其全部忽略,并将JSON反序列化为如下所示的对象:

class客户{
公共字符串CustomerID{get;set;}
公共字符串CustomerCurrencyID{get;set;}
}

我目前正在编写一个自定义JsonConverter来处理这个问题,所以如果我走上了正确的道路,请告诉我,但是这里的任何提示/技巧都将不胜感激

您可以使用以下通用命令来执行此操作:

public class WrapWithValueConverter<TValue> : JsonConverter
{
    // Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
    class DTO { [JsonConverter(typeof(NoConverter))] public TValue value { get; set; } public object GetValue() => value; }

    public override bool CanConvert(Type objectType) => typeof(TValue).IsAssignableFrom(objectType);
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => serializer.Serialize(writer, new DTO { value = (TValue)value });

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => serializer.Deserialize<DTO>(reader)?.GetValue();
}

public class NoConverter : JsonConverter
{
    // NoConverter taken from this answer https://stackoverflow.com/a/39739105/3744182
    // By https://stackoverflow.com/users/3744182/dbc
    // To https://stackoverflow.com/questions/39738714/selectively-use-default-json-converter
    public override bool CanConvert(Type objectType)  { throw new NotImplementedException(); /* This converter should only be applied via attributes */ }
    public override bool CanRead => false;
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
public class WrapEnumWithValueConverter<TEnum> : JsonConverter where TEnum: Enum
{
    // Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
    class DTO { [JsonConverter(typeof(StringEnumConverter))] public TEnum value { get; set; } public object GetValue() => value; }

    public override bool CanConvert(Type objectType) => typeof(TEnum).IsAssignableFrom(objectType);

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => serializer.Serialize(writer, new DTO { value = (TEnum)value });

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => serializer.Deserialize<DTO>(reader)?.GetValue();
}
演示小提琴2

如果您的值是
enum
,并且希望将其序列化为字符串,则可以使用以下内容将
NoConverter
替换为:

public class WrapWithValueConverter<TValue> : JsonConverter
{
    // Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
    class DTO { [JsonConverter(typeof(NoConverter))] public TValue value { get; set; } public object GetValue() => value; }

    public override bool CanConvert(Type objectType) => typeof(TValue).IsAssignableFrom(objectType);
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => serializer.Serialize(writer, new DTO { value = (TValue)value });

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => serializer.Deserialize<DTO>(reader)?.GetValue();
}

public class NoConverter : JsonConverter
{
    // NoConverter taken from this answer https://stackoverflow.com/a/39739105/3744182
    // By https://stackoverflow.com/users/3744182/dbc
    // To https://stackoverflow.com/questions/39738714/selectively-use-default-json-converter
    public override bool CanConvert(Type objectType)  { throw new NotImplementedException(); /* This converter should only be applied via attributes */ }
    public override bool CanRead => false;
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
public class WrapEnumWithValueConverter<TEnum> : JsonConverter where TEnum: Enum
{
    // Here we take advantage of the fact that a converter applied to a property has highest precedence to avoid an infinite recursion.
    class DTO { [JsonConverter(typeof(StringEnumConverter))] public TEnum value { get; set; } public object GetValue() => value; }

    public override bool CanConvert(Type objectType) => typeof(TEnum).IsAssignableFrom(objectType);

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => serializer.Serialize(writer, new DTO { value = (TEnum)value });

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        => serializer.Deserialize<DTO>(reader)?.GetValue();
}
公共类WrapEnumWithValueConverter:JsonConverter其中TEnum:Enum
{
//在这里,我们利用应用于属性的转换器具有最高优先级这一事实来避免无限递归。
类DTO{[JsonConverter(typeof(StringEnumConverter))]公共TEnum值{get;set;}公共对象GetValue()=>value;}
public override bool CanConvert(Type objectType)=>typeof(TEnum)。IsAssignableFrom(objectType);
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
=>serializer.Serialize(writer,newdto{value=(TEnum)value});
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
=>序列化程序.反序列化(读取器)?.GetValue();
}

演示fiddle#3。

即,或者创建表示所需格式的C#对象,编写C#代码以从坏对象映射到好对象,并序列化它。我会选择自定义序列化程序,但这主要是个人偏好。@Jonesopolis问题是,我更倾向于自定义转换器,因为当我想将我的对象发送回API时,它需要采用它们的格式。这很有意义。或者双向映射-具有两种方法的扩展类
静态GoodApiObject ConvertFromBadAPIObject(此badApiObject)
静态badApiObject ConvertBacktoDapiObject(此GoodApiObject)
。根据场景的不同,将第三方集成封装在您自己的对象中可能是一种很好的做法。这看起来确实非常有效,但是我很难完全理解代码本身。我来看看是否能解决所有这些问题。@Daedalus-转换器通过用必要的结构序列化a来工作。然后还有一些额外的复杂性,以防止递归调用转换器来序列化
DTO.Value
,这将导致堆栈溢出异常。如果“Value”不是字符串(如bool/decimal/int),这是否可以正常工作?@Daedalus-是的,它设计用于任何类型,只需为
TValue
使用正确的通用参数,例如
WrapWithValueConverter
WrapWithValueConverter
WrapWithValueConverter
等。啊,好吧,那么如果返回的对象包含所有这些参数,注释方法会更好?