考虑这两个类:
public Class Base {
public string Id {get; set;}
public string Name {get; set;}
public string LastName {get; set;}
}
派生类:
public Class Derived : Base {
public string Address {get; set;}
public DateTime DateOfBirth {get; set;}
}
使用 Json.Net 序列化派生类时:
Derived record = new Derived record(); {// Initialize here...}
JsonConvert.SerializeObject(record);
默认情况下,首先显示派生类的属性:
{
"address": "test",
"date_of_birth" : "10/10/10",
"id" : 007,
"name" : "test name",
"last_name": "test last name"
}
我需要什么:
{
"id" : 007,
"name" : "test name",
"last_name": "test last name"
"address": "test",
"date_of_birth" : "10/10/10",
}
问题
在序列化派生类时,是否可以首先使用基类属性(对两个类的每个属性不使用[JsonProperty(Order=)]
)?
答案 0 :(得分:16)
根据JSON standard,JSON对象是一组无序的名称/值对。所以我的建议是不要担心房产秩序。不过,您可以通过创建自己的ContractResolver
继承标准contract resolvers之一,然后覆盖CreateProperties
来获得所需的订单:
public class BaseFirstContractResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
static BaseFirstContractResolver instance;
static BaseFirstContractResolver() { instance = new BaseFirstContractResolver(); }
public static BaseFirstContractResolver Instance { get { return instance; } }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
if (properties != null)
return properties.OrderBy(p => p.DeclaringType.BaseTypesAndSelf().Count()).ToList();
return properties;
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
然后使用它:
var settings = new JsonSerializerSettings { ContractResolver = BaseFirstContractResolver.Instance };
var json = JsonConvert.SerializeObject(derived, Formatting.Indented, settings);
答案 1 :(得分:16)
作为补充,另一种不同于接受答案的方法是使用[JsonProperty(Order = -2)]
;您可以按照以下方式修改基类:
public class Base
{
[JsonProperty(Order = -2)]
public string Id { get; set; }
[JsonProperty(Order = -2)]
public string Name { get; set; }
[JsonProperty(Order = -2)]
public string LastName { get; set; }
}
将顺序设置为-2的原因是没有显式顺序的任何属性默认情况下的顺序为-1。因此,您必须为所有子项属性提供订单,或者只是设置您的基类&#39;属性为-2。
答案 2 :(得分:1)
如果您使用的是ASP.NET Core,请勿覆盖重要的合约解析程序设置provided by default。从@ dbc的回答开始,你可以这样做:
class DataContractJsonResolver : DefaultContractResolver
{
public DataContractJsonResolver()
{
NamingStrategy = new CamelCaseNamingStrategy();
}
protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
{
return base.CreateProperties( type, memberSerialization )
.OrderBy( p => BaseTypesAndSelf( p.DeclaringType ).Count() ).ToList();
IEnumerable<Type> BaseTypesAndSelf( Type t )
{
while ( t != null ) {
yield return t;
t = t.BaseType;
}
}
}
}
答案 3 :(得分:0)
我也考虑采用'dbc'的答案,但是用以下命令替换-(OrderBy()'表达式,该表达式(-不依赖基类具有比派生类更多的属性): / p>
.OrderBy(
p =>
p.DeclaringType == type
? 2
: 1)
.ThenBy(
p =>
p.Order ?? -1)
然后您不需要“ TypeExtensions”,但它会重复“ p.Order”排序(已经在基类中进行了);在有时间和思想的情况下,可能会有更好/更有效的方法来完成此操作。