gpt4 book ai didi

c# - JsonSerializer.CreateDefault().Populate(..) 重置我的值

转载 作者:太空宇宙 更新时间:2023-11-03 15:12:39 26 4
gpt4 key购买 nike

我有以下类(class):

public class MainClass
{
public static MainClass[] array = new MainClass[1]
{
new MainClass
{
subClass = new SubClass[2]
{
new SubClass
{
variable1 = "my value"
},
new SubClass
{
variable1 = "my value"
}
}
}
};

public SubClass[] subClass;
[DataContract]
public class SubClass
{
public string variable1 = "default value";
[DataMember] // because only variable2 should be saved in json
public string variable2 = "default value";
}
}

我保存如下:

File.WriteAllText("data.txt", JsonConvert.SerializeObject(new
{
MainClass.array
}, new JsonSerializerSettings { Formatting = Formatting.Indented }));

数据.txt:

{
"array": [
{
"subClass": [
{
"variable2": "value from json"
},
{
"variable2": "value from json"
}
]
}
]
}

然后我像这样反序列化并填充我的对象:

JObject json = JObject.Parse(File.ReadAllText("data.txt"));
if (json["array"] != null)
{
for (int i = 0, len = json["array"].Count(); i < len; i++)
{
using (var sr = json["array"][i].CreateReader())
{
JsonSerializer.CreateDefault().Populate(sr, MainClass.array[i]);
}
}
}

但是,当我打印以下变量时:

Console.WriteLine(MainClass.array[0].subClass[0].variable1);
Console.WriteLine(MainClass.array[0].subClass[0].variable2);
Console.WriteLine(MainClass.array[0].subClass[1].variable1);
Console.WriteLine(MainClass.array[0].subClass[1].variable2);

那么它的输出是:

default value
value from json
default value
value from json

但应该使用“我的值”而不是“默认值”,因为这是我在创建类实例时使用的值,而 JsonSerializer 应该只使用 json 中的值填充对象。

如何在不重置不包含在 json 中的属性的情况下正确填充整个对象?

最佳答案

看起来好像 JsonSerializer.Populate() 缺少 MergeArrayHandling 适用于 JObject.Merge() 的设置.通过测试我发现:

  • 填充数组成员或某些其他类型的只读集合似乎像 MergeArrayHandling.Replace 一样工作.

    这就是您遇到的行为——现有数组和其中的所有项都被丢弃并替换为包含具有默认值的新建项的新数组。相反,您需要 MergeArrayHandling.Merge : 将数组项合并在一起,按索引匹配。

  • 填充作为读/写集合的成员,例如 List<T>看起来像 MergeArrayHandling.Concat .

似乎合理request an enhancementPopulate()支持这个设置——虽然我不知道实现起来有多容易。至少 Populate() 的文档应该解释这种行为。

与此同时,这里有一个自定义 JsonConverter具有必要的逻辑来模拟 MergeArrayHandling.Merge 的行为:

public class ArrayMergeConverter<T> : ArrayMergeConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsArray && objectType.GetArrayRank() == 1 && objectType.GetElementType() == typeof(T);
}
}

public class ArrayMergeConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (!objectType.IsArray)
throw new JsonSerializationException(string.Format("Non-array type {0} not supported.", objectType));
var contract = (JsonArrayContract)serializer.ContractResolver.ResolveContract(objectType);
if (contract.IsMultidimensionalArray)
throw new JsonSerializationException("Multidimensional arrays not supported.");
if (reader.TokenType == JsonToken.Null)
return null;
if (reader.TokenType != JsonToken.StartArray)
throw new JsonSerializationException(string.Format("Invalid start token: {0}", reader.TokenType));
var itemType = contract.CollectionItemType;
var existingList = existingValue as IList;
IList list = new List<object>();
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
case JsonToken.Null:
list.Add(null);
break;
case JsonToken.EndArray:
var array = Array.CreateInstance(itemType, list.Count);
list.CopyTo(array, 0);
return array;
default:
// Add item to list
var existingItem = existingList != null && list.Count < existingList.Count ? existingList[list.Count] : null;
if (existingItem == null)
{
existingItem = serializer.Deserialize(reader, itemType);
}
else
{
serializer.Populate(reader, existingItem);
}
list.Add(existingItem);
break;
}
}
// Should not come here.
throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
}

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

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

public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}

然后将转换器添加到您的 subClass成员如下:

    [JsonConverter(typeof(ArrayMergeConverter))]
public SubClass[] subClass;

或者,如果您不想将 Json.NET 属性添加到您的数据模型,您可以在序列化程序设置中添加它:

    var settings = new JsonSerializerSettings
{
Converters = new[] { new ArrayMergeConverter<MainClass.SubClass>() },
};
JsonSerializer.CreateDefault(settings).Populate(sr, MainClass.array[i]);

该转换器专为数组设计,但可以轻松地为读/写集合创建类似的转换器,例如 List<T> .

关于c# - JsonSerializer.CreateDefault().Populate(..) 重置我的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40422136/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com