我只想使用Json.NET序列化对象的某些属性。
我使用的是类似Json.net serialize only certain properties中所述的解决方案。
我的问题是我每次都要选择不同的属性,并且出于性能原因,对CreateContract
的调用(依次调用CreateProperties
)被缓存(源代码:https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs)。
有没有一种方法可以只序列化我想要的属性,每次都指定不同的属性,而不必重写整个DefaultContractResolver
类?
这是一个显示此问题的程序:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
class Person {
public int Id;
public string FirstName;
public string LastName;
}
public class SelectedPropertiesContractResolver<T> : CamelCasePropertyNamesContractResolver {
HashSet<string> _selectedProperties;
public SelectedPropertiesContractResolver(IEnumerable<string> selectedProperties) {
_selectedProperties = selectedProperties.ToHashSet();
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
if (type == typeof(T)) {
return base.CreateProperties(type, memberSerialization)
.Where(p => _selectedProperties.Contains(p.PropertyName, StringComparer.OrdinalIgnoreCase)).ToList();
}
return base.CreateProperties(type, memberSerialization);
}
}
class Program {
static void Main(string[] args) {
var person = new Person { Id = 1, FirstName = "John", LastName = "Doe" };
var serializer1 = new JsonSerializer {
ContractResolver = new SelectedPropertiesContractResolver<Person>(new[] { "Id", "FirstName" })
};
// This will contain only Id and FirstName, as expected
string json1 = JObject.FromObject(person, serializer1).ToString();
var serializer2 = new JsonSerializer {
ContractResolver = new SelectedPropertiesContractResolver<Person>(new[] { "LastName" })
};
// Since calls to CreateProperties are cached, this will contain Id and FirstName as well, instead of LastName.
string json2 = JObject.FromObject(person, serializer2).ToString();
}
}
答案 0 :(得分:3)
您可以覆盖ResolveContract
方法并始终创建新协定(甚至更好-根据T
和_selectedProperties
类型的内容提供自己喜欢的缓存方式)
public class SelectedPropertiesContractResolver<T> : CamelCasePropertyNamesContractResolver {
...
public override JsonContract ResolveContract(Type type)
{
return CreateContract(type);
}
}
答案 1 :(得分:0)
您可以使用代码来解决您的任务:
static void Main(string[] args)
{
var myObject = new {Id = 123, Name = "Test", IsTest = true};
var propertyForSerialization = new List<string> { "Id", "Name" };
var result = GetSerializedObject(myObject, propertyForSerialization);
}
private static string GetSerializedObject(object objForSerialize, List<string> propertyForSerialization)
{
var customObject = new ExpandoObject() as IDictionary<string, Object>;
Type myType = objForSerialize.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in props)
{
foreach (var propForSer in propertyForSerialization)
{
if (prop.Name == propForSer)
{
customObject.Add(prop.Name, prop.GetValue(objForSerialize, null));
}
}
}
return JsonConvert.SerializeObject(customObject);
}
答案 2 :(得分:0)
基于评论和所选答案的几种可能的解决方案。
使用条件序列化:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public interface ISerializeSelectedPropertiesOnly {
bool ShouldSerialize(string propertyName);
}
public class Person : ISerializeSelectedPropertiesOnly {
public int Id;
public string FirstName;
public string LastName;
public HashSet<string> _propertiesToSerialize;
public bool ShouldSerialize(string propertyName) {
return _propertiesToSerialize?.Contains(propertyName, StringComparer.OrdinalIgnoreCase) ?? true;
}
}
public class SelectedPropertiesContractResolver : CamelCasePropertyNamesContractResolver {
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (typeof(ISerializeSelectedPropertiesOnly).IsAssignableFrom(property.DeclaringType)) {
property.ShouldSerialize = instance => ((ISerializeSelectedPropertiesOnly)instance).ShouldSerialize(property.PropertyName);
}
return property;
}
}
class Program {
static void Main(string[] args) {
var person = new Person { Id = 1, FirstName = "John", LastName = "Doe" };
person._propertiesToSerialize = new HashSet<string> { "Id", "FirstName" };
var serializer = new JsonSerializer {
ContractResolver = new SelectedPropertiesContractResolver()
};
string json1 = JObject.FromObject(person, serializer).ToString();
person._propertiesToSerialize = new HashSet<string> { "LastName" };
string json2 = JObject.FromObject(person, serializer).ToString();
}
}
覆盖ResolveContract
:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
public class Person {
public int Id;
public string FirstName;
public string LastName;
}
public class SelectedPropertiesContractResolver<T> : CamelCasePropertyNamesContractResolver {
HashSet<string> _selectedProperties;
public SelectedPropertiesContractResolver(IEnumerable<string> selectedProperties) {
_selectedProperties = selectedProperties.ToHashSet();
}
public override JsonContract ResolveContract(Type type) {
return CreateContract(type);
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
if (type == typeof(T)) {
return base.CreateProperties(type, memberSerialization)
.Where(p => _selectedProperties.Contains(p.PropertyName, StringComparer.OrdinalIgnoreCase)).ToList();
}
return base.CreateProperties(type, memberSerialization);
}
}
class Program {
static void Main(string[] args) {
var person = new Person { Id = 1, FirstName = "John", LastName = "Doe" };
var serializer = new JsonSerializer {
ContractResolver = new SelectedPropertiesContractResolver<Person>(new HashSet<string> { "Id", "FirstName" })
};
string json1 = JObject.FromObject(person, serializer).ToString();
serializer = new JsonSerializer {
ContractResolver = new SelectedPropertiesContractResolver<Person>(new HashSet<string> { "LastName" })
};
string json2 = JObject.FromObject(person, serializer).ToString();
Console.WriteLine(json1);
Console.WriteLine(json2);
}
}