我正在研究Entity Framework项目。我想序列化一堆实体类实例。我将它们绑定(bind)到一个容器类中:
public class Pseudocontext
{
public List<Widget> widgets;
public List<Thing> things;
JsonSerializer serializer = new JsonSerializer();
serializer.PreserveReferencesHandling = PreserveReferencesHandling.None;
public class WhatDecadeIsItAgain : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
JsonContract contract = base.CreateContract(objectType);
if (objectType.IsPrimitive || objectType == typeof(DateTime) || objectType == typeof(string)
|| objectType == typeof(Pseudocontext) || objectType.Name.Contains("List"))
{
contract.Converter = base.CreateContract(objectType).Converter;
}
else
{
contract.Converter = myDefaultConverter;
}
return contract;
}
private static GeeThisSureTakesALotOfClassesConverter myDefaultConverter = new GeeThisSureTakesALotOfClassesConverter();
}
public class GeeThisSureTakesALotOfClassesConverter : Newtonsoft.Json.Converters.CustomCreationConverter<object>
{
public override object Create(Type objectType)
{
return null;
}
}
最佳答案
首先,要解决引用循环的问题-PreserveReferencesHandling
设置控制Json.Net是否发出$id
和$ref
来跟踪对象间引用。如果将其设置为None
并且对象图包含循环,则还需要将ReferenceLoopHandling
设置为Ignore
以防止错误。
现在,要使Json.Net完全忽略所有对象引用并仅序列化基本属性(当然,在Pseudocontext
类中除外),您确实需要按照您的建议自定义Contract Resolver。但是不用担心,它并不像您想象的那么难。解析器可以为每个属性注入(inject)ShouldSerialize
方法,以控制该属性是否应包含在输出中。因此,您所需要做的就是从默认解析器派生您的解析器,然后覆盖CreateProperty
方法,以便它适当地设置ShouldSerialize
。 (尽管可以用这种方法解决此问题,但是这里不需要自定义的JsonConverter
。但是,这将需要更多的代码。)
这是解析器的代码:
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (prop.DeclaringType != typeof(PseudoContext) &&
prop.PropertyType.IsClass &&
prop.PropertyType != typeof(string))
{
prop.ShouldSerialize = obj => false;
}
return prop;
}
}
class Program
{
static void Main(string[] args)
{
// Set up some dummy data complete with reference loops
Thing t1 = new Thing { Id = 1, Name = "Flim" };
Thing t2 = new Thing { Id = 2, Name = "Flam" };
Widget w1 = new Widget
{
Id = 5,
Name = "Hammer",
IsActive = true,
Price = 13.99M,
Created = new DateTime(2013, 12, 29, 8, 16, 3),
Color = Color.Red,
};
w1.RelatedThings = new List<Thing> { t2 };
t2.RelatedWidgets = new List<Widget> { w1 };
Widget w2 = new Widget
{
Id = 6,
Name = "Drill",
IsActive = true,
Price = 45.89M,
Created = new DateTime(2014, 1, 22, 2, 29, 35),
Color = Color.Blue,
};
w2.RelatedThings = new List<Thing> { t1 };
t1.RelatedWidgets = new List<Widget> { w2 };
// Here is the container class we wish to serialize
PseudoContext pc = new PseudoContext
{
Things = new List<Thing> { t1, t2 },
Widgets = new List<Widget> { w1, w2 }
};
// Serializer settings
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Formatting = Formatting.Indented;
// Do the serialization and output to the console
string json = JsonConvert.SerializeObject(pc, settings);
Console.WriteLine(json);
}
class PseudoContext
{
public List<Thing> Things { get; set; }
public List<Widget> Widgets { get; set; }
}
class Thing
{
public int Id { get; set; }
public string Name { get; set; }
public List<Widget> RelatedWidgets { get; set; }
}
class Widget
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public decimal Price { get; set; }
public DateTime Created { get; set; }
public Color Color { get; set; }
public List<Thing> RelatedThings { get; set; }
}
enum Color { Red, White, Blue }
}
{
"Things": [
{
"Id": 1,
"Name": "Flim"
},
{
"Id": 2,
"Name": "Flam"
}
],
"Widgets": [
{
"Id": 5,
"Name": "Hammer",
"IsActive": true,
"Price": 13.99,
"Created": "2013-12-29T08:16:03",
"Color": 0
},
{
"Id": 6,
"Name": "Drill",
"IsActive": true,
"Price": 45.89,
"Created": "2014-01-22T02:29:35",
"Color": 2
}
]
}
https://stackoverflow.com/questions/21292010/