我想为此使用 JavaScriptSerializer,因为我担心有多少东西可能会中断,而且我无法在客户端更改任何内容。
如果 Json.Net 是最好的方法,那么我会尝试一下,但我需要一个示例。
我有这个课
类定义
[DataContract]
[Serializable]
public class Family
{
[DataMember(Order = 0)]
public List<Member> members { get; set; }
}
[DataContract]
[Serializable]
public class Member
{
[DataMember(Order = 0)]
public string FName { get; set; }
[DataMember(Order = 1)]
public string LName { get; set; }
[DataMember(Order = 2)]
public string DOB { get; set; }
[DataMember(Order = 3)]
public string Gender { get; set; }
[DataMember(Order = 4)]
public string Type { get; set; }
}
我正在反序列化的 JSON 如下所示
杰伦示例
[
{
"Family": [
{
"FName": "Jane",
"LName": "Prospect",
"DOB": "04/01/1980",
"Gender": "Female",
"Type": "Adult"
},
{...}
]
},
{
"OptionChoice": 34,
"OptionText": "Aquatics"
},
{...},
{...}
]
我可以很好地反序列化答案对象(选项选择,选项文本)。Hower 答案对象有一个充满空值的附加项,它正在解析 JSON 的"家庭"部分。我真的不想这样。
当我尝试反序列化家庭部分时,出现错误
Type 'Family' is not supported for deserialization of an array.
它说它有一个 Family.members 的空值。是否正在寻找"家庭": [ "成员": {...},{...}] ?
如何在不更改 JSON 示例的情况下使其工作?
dbc 后更新答案:
这是我的模型
[DataContract]
[Serializable]
public class Answer
{
[DataMember(Order = 2, EmitDefaultValue = false)]
public int FormID { get; set; }
[DataMember(Order = 3,EmitDefaultValue = false)]
public int Question { get; set; }
[DataMember(Order = 5)]
public int OptionChoice { get; set; }
[DataMember(Order = 6,IsRequired = false)]
public string OptionText { get; set; }
[DataMember(Order = 5, EmitDefaultValue = false)]
public bool lockAnswer { get; set; }
[DataMember(Order = 1,EmitDefaultValue= false)]
public List<FamilyMember> Family { get; set; }
}
[DataContract]
[Serializable]
public class FamilyMember
{
[DataMember(Order = 0)]
public string FName { get; set; }
[DataMember(Order = 1)]
public string LName { get; set; }
[DataMember(Order = 2)]
public string DOB { get; set; }
[DataMember(Order = 3)]
public string Gender { get; set; }
[DataMember(Order = 4)]
public string Type { get; set; }
}
在我创建SO更新的这一点上,我解决了橡皮鸭调试的问题
事实证明,我有一些正则表达式正在剥离所有"["和"]",然后手动将它们添加回来,但仅限于末端。
顺便说一句,这个很酷的比较工具 http://pro.jsonlint.com/帮助了。
谢谢!如果将来有人阅读本文并希望展示一种可测试的方法,请执行以下操作 JSON.net(我尝试过但卡住了),请这样做。
您的问题包括两个相关问题:
-
加载
Family
列表的异常。这里的问题是,正如您所怀疑的那样,没有对应于
members
的属性。 您的 JSON 具有一个对象数组,每个对象可能都有一个数组值属性Family
。 因此,您的数据模型应如下所示:public class ResponseItem { public int? OptionChoice { get; set; } public string OptionText { get; set; } public List<FamilyMember> Family { get; set; } // Other fields not shown from {...} } public class FamilyMember { public string FName { get; set; } public string LName { get; set; } public string DOB { get; set; } public string Gender { get; set; } public string Type { get; set; } }
-
您声明,"Hower 答案对象有一个充满空值的附加项,它正在解析 JSON 的 Family 部分。我真的不想这样。 这可以通过将 JSON 反序列化为多态数组来完成,其中每个可能的派生类型只有最少数量的字段。 但是,由于 JSON 中没有
__type
信息,因此您需要添加一些稍微挑剔的逻辑来为每个数组元素选择正确的具体类型。 您的数据模型如下所示:public interface IResponseItem // base interface for all possible responses { } public class FamilyResponse : IResponseItem { public List<FamilyMember> Family { get; set; } } public class OptionsResponse : IResponseItem { public int OptionChoice { get; set; } public string OptionText { get; set; } }
在像这样的复杂序列化情况下,人们似乎更喜欢 Json.NET,但是根据您的问题,
JavaScriptSerializer
仍然是可能的。 必须对JavaScriptConverter
进行编码,以便通过匹配属性名称从基IResponseItem
类型中选择适当的派生类型,例如:public class PolymorphicTypeConverter : JavaScriptConverter { public Type BaseType { get; private set; } public Type[] DerivedTypes { get; private set; } public PolymorphicTypeConverter(Type baseType, IEnumerable<Type> derivedTypes) { this.BaseType = baseType; this.DerivedTypes = derivedTypes.ToArray(); } static MemberInfo FindMember(Type type, string name) { try { var propInfo = type.GetProperty(name, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public); if (propInfo != null && propInfo.GetSetMethod() != null && propInfo.GetIndexParameters().Length == 0) return propInfo; var fieldInfo = type.GetField(name, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public); if (fieldInfo != null) return fieldInfo; } catch (AmbiguousMatchException) { return null; } return null; } IEnumerable<Type> AncestorsAndSelf(Type type) { for (; type != null; type = type.BaseType) if (DerivedTypes.Contains(type)) yield return type; } Type FindUniqueTypeMatch(IDictionary<string, object> jsonProperties) { List<Type> matches = new List<Type>(); foreach (var type in DerivedTypes) { if (type.IsInterface) continue; // Bug? bool isMatch = true; foreach (var name in jsonProperties.Keys) { if (FindMember(type, name) == null) { isMatch = false; break; } } if (isMatch) { matches.Add(type); } } if (matches.Count == 0) return null; else if (matches.Count == 1) return matches[0]; else { // Multiple matches. // If there is a common base type to all matches, return it. Otherwise, give up. var candidates = AncestorsAndSelf(matches[0]).Reverse(); foreach (var match in matches.Skip(1)) { candidates = candidates.Zip(AncestorsAndSelf(match).Reverse(), (t1, t2) => (t1 == t2 ? t1 : null)).Where(t => t != null); } return candidates.LastOrDefault(); } } public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { var subtype = FindUniqueTypeMatch(dictionary); if (subtype == null) throw new JsonSerializationException(); var method = serializer.GetType().GetMethod("ConvertToType"); var generic = method.MakeGenericMethod(subtype); return generic.Invoke(serializer, new object [] { dictionary } ); } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { // Should never be called. throw new NotImplementedException(); } public override IEnumerable<Type> SupportedTypes { get { return new Type[] { BaseType }; } } }
仅当 JSON 数组中的每个对象具有与派生类型数组中的一种且仅一种类型匹配的属性时,这才有效。 如果无法保证这一点,例如,由于未序列化空字段导致多个匹配,则需要增强转换器以获得最佳猜测匹配。
然后这样称呼它:
var serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new JavaScriptConverter[] { new PolymorphicTypeConverter(typeof(IResponseItem), new Type[] { typeof(FamilyResponse), typeof(OptionsResponse) }) }); var responseArray = serializer.Deserialize<IResponseItem[]>(json);