C# 将两个值反序列化为同一属性

C# 将两个值反序列化为同一属性,c#,json.net,C#,Json.net,我有一个客户端,它可以调用一个服务的两个不同版本 一个服务只发送一个值: { "value" : { ... } } 第二个服务始终返回多个值: { "values" : [ { ... }, { ... } ] } 理想情况下,我希望在我的客户机类中用一个对象来表示它,这样用户就不会看到它是一个值还是多个值 public class MyValues { public List<Stuff> Values { get; set; } pub

我有一个客户端,它可以调用一个服务的两个不同版本

一个服务只发送一个值:

{
  "value" : { ... }
}
第二个服务始终返回多个值:

{
  "values" : [ 
    { ... },
    { ... }
  ]
}
理想情况下,我希望在我的客户机类中用一个对象来表示它,这样用户就不会看到它是一个值还是多个值

public class MyValues
{
  public List<Stuff> Values { get; set; }
  public Thing Other { get; set; }
}
公共类MyValues
{
公共列表值{get;set;}
公共事物其他{get;set;}
}
我认为实现这一点的唯一方法是使用一个自定义的
JsonConverter
类,我将其应用于
MyValues
,但我真的只想在反序列化属性
value
时做一些自定义的事情。我似乎不知道IContractResolver是否是一种更好的方法(例如,以某种方式将幻影属性附加到MyValues,该属性反序列化
,并将其放入


如果我创建了一个自定义转换器,如何告诉它正常地反序列化其他所有内容(例如,如果
其他
有一个额外的属性,确保它们得到了适当的处理,等等)

而不是编写
JsonConverter
,您可以在
MyValues
上设置一个仅属性
,如下所示:

public class MyValues
{
    [JsonProperty]
    Stuff Value
    {
        set
        {
            (Values = Values ?? new List<Stuff>(1)).Clear();
            Values.Add(value);
        }
    }

    public List<Stuff> Values { get; set; }
    public Thing Other { get; set; }
}
class MyValuesConverter : CustomPropertyConverterBase<MyValues>
{
    protected override void ProcessCustomProperties(JObject obj, MyValues value, JsonSerializer serializer)
    {
        // Remove the value property for manual deserialization, and deserialize
        var jValue = obj.GetValue("value", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
        if (jValue != null)
        {
            (value.Values = value.Values ?? new List<Stuff>()).Clear();
            value.Values.Add(jValue.ToObject<Stuff>(serializer));
        }
    }
}

public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var jObj = JObject.Load(reader);
        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
        var value = existingValue as T ?? (T)contract.DefaultCreator();

        ProcessCustomProperties(jObj, value, serializer);

        // Populate the remaining properties.
        using (var subReader = jObj.CreateReader())
        {
            serializer.Populate(subReader, value);
        }

        return value;
    }

    protected abstract void ProcessCustomProperties(JObject obj, T value, JsonSerializer serializer);

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static class JsonExtensions
{
    public static JToken RemoveFromLowestPossibleParent(this JToken node)
    {
        if (node == null)
            return null;
        var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
        if (contained != null)
            contained.Remove();
        // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
        if (node.Parent is JProperty)
            ((JProperty)node.Parent).Value = null;
        return node;
    }
}
公共类MyValues
{
[JsonProperty]
物品价值
{
设置
{
(值=值??新列表(1)).Clear();
增加(价值);
}
}
公共列表值{get;set;}
公共事物其他{get;set;}
}

如果标记为,则它可以是公共的或私有的。在这种情况下,如果在Json中遇到单例
“Value”
属性,则Json.NET将调用
值设置器,如果数组
“Value”,则调用
值设置器遇到了
属性。由于只设置了属性,因此只有数组属性将被重新序列化。

您可以在
MyValues
上创建一个只设置属性
,而不是编写
JsonConverter
,如下所示:

public class MyValues
{
    [JsonProperty]
    Stuff Value
    {
        set
        {
            (Values = Values ?? new List<Stuff>(1)).Clear();
            Values.Add(value);
        }
    }

    public List<Stuff> Values { get; set; }
    public Thing Other { get; set; }
}
class MyValuesConverter : CustomPropertyConverterBase<MyValues>
{
    protected override void ProcessCustomProperties(JObject obj, MyValues value, JsonSerializer serializer)
    {
        // Remove the value property for manual deserialization, and deserialize
        var jValue = obj.GetValue("value", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
        if (jValue != null)
        {
            (value.Values = value.Values ?? new List<Stuff>()).Clear();
            value.Values.Add(jValue.ToObject<Stuff>(serializer));
        }
    }
}

public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var jObj = JObject.Load(reader);
        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
        var value = existingValue as T ?? (T)contract.DefaultCreator();

        ProcessCustomProperties(jObj, value, serializer);

        // Populate the remaining properties.
        using (var subReader = jObj.CreateReader())
        {
            serializer.Populate(subReader, value);
        }

        return value;
    }

    protected abstract void ProcessCustomProperties(JObject obj, T value, JsonSerializer serializer);

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static class JsonExtensions
{
    public static JToken RemoveFromLowestPossibleParent(this JToken node)
    {
        if (node == null)
            return null;
        var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
        if (contained != null)
            contained.Remove();
        // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
        if (node.Parent is JProperty)
            ((JProperty)node.Parent).Value = null;
        return node;
    }
}
公共类MyValues
{
[JsonProperty]
物品价值
{
设置
{
(值=值??新列表(1)).Clear();
增加(价值);
}
}
公共列表值{get;set;}
公共事物其他{get;set;}
}
如果标记为,则它可以是公共的或私有的。在这种情况下,如果在Json中遇到单例
“Value”
属性,则Json.NET将调用
值设置器,如果数组
“Value”,则调用
值设置器遇到
属性。由于只设置了该属性,因此只有数组属性将被重新序列化。

要创建一个对某些类型的属性进行特殊处理但对其余属性使用默认处理的,可以将JSON加载到,分离并处理自定义属性,然后从e> JObject
与,类似于:

public class MyValues
{
    [JsonProperty]
    Stuff Value
    {
        set
        {
            (Values = Values ?? new List<Stuff>(1)).Clear();
            Values.Add(value);
        }
    }

    public List<Stuff> Values { get; set; }
    public Thing Other { get; set; }
}
class MyValuesConverter : CustomPropertyConverterBase<MyValues>
{
    protected override void ProcessCustomProperties(JObject obj, MyValues value, JsonSerializer serializer)
    {
        // Remove the value property for manual deserialization, and deserialize
        var jValue = obj.GetValue("value", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
        if (jValue != null)
        {
            (value.Values = value.Values ?? new List<Stuff>()).Clear();
            value.Values.Add(jValue.ToObject<Stuff>(serializer));
        }
    }
}

public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var jObj = JObject.Load(reader);
        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
        var value = existingValue as T ?? (T)contract.DefaultCreator();

        ProcessCustomProperties(jObj, value, serializer);

        // Populate the remaining properties.
        using (var subReader = jObj.CreateReader())
        {
            serializer.Populate(subReader, value);
        }

        return value;
    }

    protected abstract void ProcessCustomProperties(JObject obj, T value, JsonSerializer serializer);

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static class JsonExtensions
{
    public static JToken RemoveFromLowestPossibleParent(this JToken node)
    {
        if (node == null)
            return null;
        var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
        if (contained != null)
            contained.Remove();
        // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
        if (node.Parent is JProperty)
            ((JProperty)node.Parent).Value = null;
        return node;
    }
}
类MyValuesConverter:CustomPropertyConverterBase
{
受保护的重写无效ProcessCustomProperties(JObject对象、MyValues值、JsonSerializer序列化程序)
{
//删除手动反序列化的value属性,然后进行反序列化
var jValue=obj.GetValue(“value”,StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
if(jValue!=null)
{
(value.Values=value.Values??新建列表()).Clear();
value.Values.Add(jValue.ToObject(序列化程序));
}
}
}
公共抽象类CustomPropertyConverterBase:JsonConverter其中T:class
{
公共覆盖布尔CanConvert(类型objectType)
{
返回typeof(T).IsAssignableFrom(objectType);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.Null)
返回null;
var jObj=JObject.Load(读卡器);
var contract=(JsonObjectContract)序列化程序.ContractResolver.ResolveContract(objectType);
var值=现有价值为T???(T)合同。DefaultCreator();
ProcessCustomProperties(jObj、值、序列化程序);
//填充其余的属性。
使用(var subReader=jObj.CreateReader())
{
序列化程序。填充(子读取器,值);
}
返回值;
}
受保护的抽象void ProcessCustomProperties(JObject对象、T值、JsonSerializer序列化程序);
公共重写bool可以写入{get{return false;}}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
}
公共静态类JsonExtensions
{
公共静态JToken RemoveFromLowestPossibleParent(此JToken节点)
{
if(node==null)
返回null;
var contained=node.AncestorsAndSelf()。其中(t=>t.Parent是JContainer&&t.Parent.Type!=JTokenType.Property)。FirstOrDefault();
如果(包含!=null)
包含。删除();
//另外,将节点与其立即包含的属性分离--Remove()不执行此操作,即使它看起来应该这样做
如果(node.Parent是JProperty)
((JProperty)node.Parent).Value=null;
返回节点;
}
}
要创建一个对某些类型的属性进行特殊处理但对其余属性使用默认处理的,可以将JSON加载到中,分离并处理自定义属性,然后从
JObject
中填充剩余属性,如下所示:

public class MyValues
{
    [JsonProperty]
    Stuff Value
    {
        set
        {
            (Values = Values ?? new List<Stuff>(1)).Clear();
            Values.Add(value);
        }
    }

    public List<Stuff> Values { get; set; }
    public Thing Other { get; set; }
}
class MyValuesConverter : CustomPropertyConverterBase<MyValues>
{
    protected override void ProcessCustomProperties(JObject obj, MyValues value, JsonSerializer serializer)
    {
        // Remove the value property for manual deserialization, and deserialize
        var jValue = obj.GetValue("value", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent();
        if (jValue != null)
        {
            (value.Values = value.Values ?? new List<Stuff>()).Clear();
            value.Values.Add(jValue.ToObject<Stuff>(serializer));
        }
    }
}

public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var jObj = JObject.Load(reader);
        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
        var value = existingValue as T ?? (T)contract.DefaultCreator();

        ProcessCustomProperties(jObj, value, serializer);

        // Populate the remaining properties.
        using (var subReader = jObj.CreateReader())
        {
            serializer.Populate(subReader, value);
        }

        return value;
    }

    protected abstract void ProcessCustomProperties(JObject obj, T value, JsonSerializer serializer);

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static class JsonExtensions
{
    public static JToken RemoveFromLowestPossibleParent(this JToken node)
    {
        if (node == null)
            return null;
        var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
        if (contained != null)
            contained.Remove();
        // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
        if (node.Parent is JProperty)
            ((JProperty)node.Parent).Value = null;
        return node;
    }
}
类MyValuesConverter:CustomPropertyConverterBase
{
受保护的重写无效ProcessCustomProperties(JObject对象、MyValues值、JsonSerializer序列化程序)
{
//删除手动反序列化的value属性,然后进行反序列化
var jValue=obj.GetValue(“value”,StringComparison.OrdinalIgnoreCase).Re