我有一个类似的模型:
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
。
您可以简单地将模型与details
的额外字段一起使用,然后使用JsonIgnore
属性来忽略Size
和Weight
字段的序列化。因此,您的模型看起来像这样:
public class MyModel
{
[JsonProperty("name")]
public string Name { get; set; }
public Details details { get; set; }
[JsonIgnore]
public string[] Size
{
get
{
return details != null ? details.size : null;
}
set
{
if (details == null)
{
details = new Details();
}
details.size = value;
}
}
[JsonIgnore]
public string Weight
{
get
{
return details != null ? details.weight : null;
}
set
{
if (details == null)
{
details = new Details();
}
details.weight = value;
}
}
}
然后,您可以简单地序列化/避免这样的模型:
var deserializedModel = JsonConvert.DeserializeObject<MyModel>("your json string...");
var myModel = new MyModel { Name = "widget", Size = new[] { "XL", "M", "S" }, Weight = "heavy" };
string serializedObject = JsonConvert.SerializeObject(myModel);
这应该有效:
public class MyModelJsonConverter : JsonConverter
{
public override bool CanRead
{
get { return true; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(MyModel);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (objectType != typeof(MyModel))
{
throw new ArgumentException("objectType");
}
switch (reader.TokenType)
{
case JsonToken.Null:
{
return null;
}
case JsonToken.StartObject:
{
reader.Read();
break;
}
default:
{
throw new JsonSerializationException();
}
}
var result = new MyModel();
bool inDetails = false;
while (reader.TokenType == JsonToken.PropertyName)
{
string propertyName = reader.Value.ToString();
if (string.Equals("name", propertyName, StringComparison.OrdinalIgnoreCase))
{
reader.Read();
result.Name = serializer.Deserialize<string>(reader);
}
else if (string.Equals("size", propertyName, StringComparison.OrdinalIgnoreCase))
{
if (!inDetails)
{
throw new JsonSerializationException();
}
reader.Read();
result.Size = serializer.Deserialize<string[]>(reader);
}
else if (string.Equals("weight", propertyName, StringComparison.OrdinalIgnoreCase))
{
if (!inDetails)
{
throw new JsonSerializationException();
}
reader.Read();
result.Weight = serializer.Deserialize<string>(reader);
}
else if (string.Equals("details", propertyName, StringComparison.OrdinalIgnoreCase))
{
reader.Read();
if (reader.TokenType != JsonToken.StartObject)
{
throw new JsonSerializationException();
}
inDetails = true;
}
else
{
reader.Skip();
}
reader.Read();
}
if (inDetails)
{
if (reader.TokenType != JsonToken.EndObject)
{
throw new JsonSerializationException();
}
reader.Read();
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
var model = value as MyModel;
if (model == null) throw new JsonSerializationException();
writer.WriteStartObject();
writer.WritePropertyName("name");
writer.WriteValue(model.Name);
writer.WritePropertyName("details");
writer.WriteStartObject();
writer.WritePropertyName("size");
serializer.Serialize(writer, model.Size);
writer.WritePropertyName("weight");
writer.WriteValue(model.Weight);
writer.WriteEndObject();
writer.WriteEndObject();
}
}
[JsonConverter(typeof(MyModelJsonConverter))]
public class MyModel
{
public string Name { get; set; }
public string[] Size { get; set; }
public string Weight { get; set; }
}
使用类上的属性,使用它很容易:
var model = new MyModel
{
Name = "widget",
Size = new[] { "XL", "M", "S" },
Weight = "heavy"
};
string output = JsonConvert.SerializeObject(model);
// {"name":"widget","details":{"size":["XL","M","S"],"weight":"heavy"}}
var model2 = JsonConvert.DeserializeObject<MyModel>(output);
/*
{
Name = "widget",
Size = [ "XL", "M", "S" ],
Weight = "heavy"
}
*/