我无法控制我的数据源。他们构造了一个应该包含数组的JSON字符串,但它没有。此外,他们以不同的方式命名每个属性。我已经尝试了所有我知道的东西,但我不知道是不是想把它反序列化。
{ "class-A" : { "property_0" : { "item1" : "data", "item2" : "data" }, "property_1" : { "item1" : "data", "item2" : "data" }, "property_2" : { "item1" : "data", "item2" : "data" } } }
这应该是一个数组,因此我可以将其反序列化为IEnumerable< property>但缺少数组括号和附加到属性名称的下划线/数字真的让我失望。
我已经能够将字符串反序列化为单独的编号属性,然后将它们添加到集合中,但这不会起作用,因为属性的数量可能会变得很长(大约200或更多)并且我不会事先不知道JSON字符串中将包含多少属性。
有没有办法使用Newtonsoft-Json来处理这种反序列化,以便忽略属性名中的下划线/数字并将其作为数组属性名称(别名)处理?我可以控制构建代表JSON字符串的模型,但我不确定它是如何帮助的。
答案 0 :(得分:0)
我搜索过,看起来你需要一个JSONConverter。
/// <summary>
/// A JsonConverter that respects the Name property of DataMember attributes
/// applied to enumeration members, falling back to the enumeration member
/// name where no DataMember attribute exists (or where a name has not
/// been supplied). Entirely experimental, use at your own risk.
///
/// Paul O'Neill, paul@pablissimo.com, 31/07/13
/// </summary>
public class DataMemberAwareEnumJsonConverter : JsonConverter
{
private static Dictionary<Type, IEnumerable<Tuple<object, string>>> _typeNameCache =
new Dictionary<Type, IEnumerable<Tuple<object, string>>>();
public override bool CanConvert(Type objectType)
{
return objectType.IsEnum;
}
public override object ReadJson(JsonReader reader, Type type, object existingValue, JsonSerializer serializer)
{
return GetOutputValue(reader.Value.ToString(), type);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, GetOutputName(value));
}
private static string GetOutputName(object value)
{
Type type = value.GetType();
if (!type.IsEnum)
{
throw new InvalidOperationException("Type is not an enumeration");
}
var map = GetOutputMap(type);
var match = map.FirstOrDefault(x => x.Item1.Equals(value));
if (match != null)
{
return match.Item2;
}
else
{
// We're buggered if this is a flags enum so just return the string representation
return value.ToString();
}
}
private static object GetOutputValue(string serialised, Type type)
{
if (!type.IsEnum)
{
throw new InvalidOperationException("Type is not an enumeration");
}
var map = GetOutputMap(type);
var match = map.FirstOrDefault(x => x.Item2.Equals(serialised));
if (match != null)
{
// Immediate hit, just use it
return match.Item1;
}
else
{
// No hit, which suggests a straight Enum.Parse should work
// (or fail because we've been supplied nonsense)
return Enum.Parse(type, serialised);
}
}
private static IEnumerable<Tuple<object, string>> GetOutputMap(Type type)
{
IEnumerable<Tuple<object, string>> enumOutputLookup = null;
if (!_typeNameCache.TryGetValue(type, out enumOutputLookup))
{
// Index the type naively - it's unlikely we'll have more than a handful of
// enum values per type
List<Tuple<object, string>> outputNames = new List<Tuple<object, string>>();
foreach (var field in type.GetFields(BindingFlags.Static | BindingFlags.Public))
{
var dataMemberAttribute = Attribute.GetCustomAttribute(field, typeof(DataMemberAttribute)) as DataMemberAttribute;
if (dataMemberAttribute != null && !string.IsNullOrWhiteSpace(dataMemberAttribute.Name))
{
outputNames.Add(new Tuple<object, string>(field.GetValue(null), dataMemberAttribute.Name));
}
else
{
// No attribute, so go with the string representation of the field
outputNames.Add(new Tuple<object, string>(field.GetValue(null), field.Name));
}
}
enumOutputLookup = outputNames;
_typeNameCache[type] = outputNames;
}
return enumOutputLookup;
}
}
来自http://pablissimo.com/572/getting-newtonsoft-json-net-to-respect-the-datamember-name-property
和
https://gist.github.com/Pablissimo/6123242#file-datamemberawareenumjsonconverter
答案 1 :(得分:0)
我不知道这是否正是您所寻找的,但也许它会给您一些想法。
var jObject = JObject.Parse(json);
var jsonPathResult = jObject.SelectTokens("$.class-A.*");
var collection = new List<Items>();
jsonPathResult.ToList().ForEach(m => collection.Add(new Items { item1 = m.Values().ElementAt(0).ToString(), item2 = m.Values().ElementAt(1).ToString() }));
Items
public class Items
{
public string item1 { get; set; }
public string item2 { get; set; }
}
答案 2 :(得分:0)
您可以将其反序列化为C#字典,以便不同的属性名称最终成为键。
class Items
{
string item1;
string item2;
}
Dictionary<string, Dictionary<string, Items>> data = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, Items>>(json);
Dictionary<string, Items> classA = data["class-A"];
然后遍历所有索引并构建数组:
List<Items> items = new List<Items>();
int i = 0;
while (classA.ContainsKey("property_" + i.ToString()))
{
items.Add(classA["property_" + i.ToString()]);
i++;
}
答案 3 :(得分:0)
JObject response = JObject.Parse(jsonString);
JEnumerable<JToken> jTokens = response["class-A"].Children();
IList<Property> properties = new List<Property>();
foreach (var jToken in jTokens)
{
JsonProp jsonProp = jToken.First.ToObject<JsonProp>();
Property property = new Property();
property.Item1 = jsonProp.item1;
property.Item2 = jsonProp.item2;
properties.Add(property);
}