gpt4 book ai didi

c# - 我可以使用 Json.net 在一次操作中将嵌套属性序列化到我的类吗?

转载 作者:太空狗 更新时间:2023-10-29 22:22:16 25 4
gpt4 key购买 nike

假设我有一个像这样的模型:

public class MyModel
{
public string Name { get; set; }
public string[] Size { get; set; }
public string Weight { get; set; }

}

Json 是这样的:

{
"name" : "widget",
"details" : {
"size" : [
"XL","M","S",
]
"weight" : "heavy"
}
}

我一直在尝试找出一种方法来序列化我的对象,而无需为“名称”创建一个模型,为“详细信息”创建一个模型,因为这不能很好地映射到我的数据库,因此需要一些杂耍才能获得填充类。

我可以在 JsonConvert.PopulateObject() 中进行多次传递,例如:

var mod = new MyModel();

JsonConvert.PopulateObject(json.ToString(), mod);
JsonConvert.PopulateObject(json["details"].ToString(), mod);

但在我的真实代码中,我正在运行多个线程,而 PopulateObject 不是线程安全的,它会阻塞应用程序。 PopulateJsonAsync() 的评论说不要使用它,而是在 PopulateObject() 上使用 Task.Run()。

这不起作用,当我调用它时仍然锁定应用程序:

await Task.Run(() => JsonConvert.PopulateObject(response.ToString(), productDetail));

if (response["results"].HasValues)
{
await Task.Run(() => JsonConvert.PopulateObject(response["results"][0].ToString(), productDetail));
}

有一些通过了,但最终应用程序完全被线程锁定了。如果我删除 PopulateObject,所有线程都会正常终止,所以我很确定这个函数不是线程安全的。

是否有一种简洁的线程安全方法来一步填充我的对象?

最佳答案

您可以使用以下转换器来完成:

public class MyModelConverter : JsonConverter
{
[ThreadStatic]
static bool cannotWrite;

// Disables the converter in a thread-safe manner.
bool CannotWrite { get { return cannotWrite; } set { cannotWrite = value; } }

public override bool CanWrite { get { return !CannotWrite; } }

public override bool CanConvert(Type objectType)
{
return typeof(MyModel).IsAssignableFrom(objectType);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = JObject.Load(reader);
obj.SelectToken("details.size").MoveTo(obj);
obj.SelectToken("details.weight").MoveTo(obj);
using (reader = obj.CreateReader())
{
// Using "populate" avoids infinite recursion.
existingValue = (existingValue ?? new MyModel());
serializer.Populate(reader, existingValue);
}
return existingValue;
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Disabling writing prevents infinite recursion.
using (new PushValue<bool>(true, () => CannotWrite, val => CannotWrite = val))
{
var obj = JObject.FromObject(value, serializer);
var details = new JObject();
obj.Add("details", details);

obj["size"].MoveTo(details);
obj["weight"].MoveTo(details);
obj.WriteTo(writer);
}
}
}

public static class JsonExtensions
{
public static void MoveTo(this JToken token, JObject newParent)
{
if (newParent == null)
throw new ArgumentNullException();
if (token != null)
{
if (token is JProperty)
{
token.Remove();
newParent.Add(token);
}
else if (token.Parent is JProperty)
{
token.Parent.Remove();
newParent.Add(token.Parent);
}
else
{
throw new InvalidOperationException();
}
}
}
}

public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;

public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}

#region IDisposable Members

// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}

#endregion
}

然后像这样使用它:

[JsonConverter(typeof(MyModelConverter))]
public class MyModel
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("size")]
public string[] Size { get; set; }
[JsonProperty("weight")]
public string Weight { get; set; }
}

public class TestClass
{
public static void Test()
{
string json = @"{
""name"" : ""widget"",
""details"" : {
""size"" : [
""XL"",""M"",""S"",
],
""weight"" : ""heavy""
}
}";
var mod = JsonConvert.DeserializeObject<MyModel>(json);
Debug.WriteLine(JsonConvert.SerializeObject(mod, Formatting.Indented));
}
}

ReadJson() 方法很简单:反序列化为 JObject,重组适当的属性,然后填充 MyModel 类。 WriteJson 有点笨拙;转换器需要以线程安全的方式暂时禁用自身以生成“默认”JObject,然后可以对其进行重组。

关于c# - 我可以使用 Json.net 在一次操作中将嵌套属性序列化到我的类吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30175911/

25 4 0
文章推荐: c# - 如何将单个数据表列转换为 csv?
文章推荐: c# - Angular 在 ASP.NET MVC 之上,显示错误
文章推荐: Python mysql.connector cursor.lastrowid 总是返回 0
文章推荐: c# - 如何在 C# 中比较两个 list 并只保留没有重复的项目?