par*_*man 2 .net c# serialization json json.net
我有一堆域对象,我将它们序列化,发送到其他应用程序,然后使用Json.Net. 这些对象可能具有以下属性
我使用了TypeNameHandling.Auto,它将$type属性添加到与声明类型不同的类型。然而,这个设置对我的动态属性有一个不需要的副作用,即它们的类型也被声明了。
在下面的示例中,model是public dynamic Model { get; set; }在我的 C# 代码中定义的动态属性。
"model":{"$type":"<>f__AnonymousType0`3[[System.String, mscorlib],[System.String, mscorlib],[System.String, mscorlib]], ExampleAssembly","link":"http://www.google.com","name":"John"}
Run Code Online (Sandbox Code Playgroud)
当尝试在另一个程序集中反序列化此字符串时,Json.Net 无法(当然)找到ExampleAssembly. 使用该TypeNameHandling.None属性给出以下属性序列化
"model": {"link":"http://www.google.com","name":"John"}
Run Code Online (Sandbox Code Playgroud)
可以成功反序列化为dynamic. 但是,这会破坏派生类型的反序列化。
关于如何在不实现自定义IContractResolver和可能的其他自定义代码的情况下使其工作的任何想法?
我不拥有域对象,所以我不能用属性装饰它们或它们的属性,也不能允许它们实现接口等。我正在寻找的是序列化程序中省略类型的某种设置dynamics。
恕我直言,这应该可以通过设置以某种方式进行配置,我只是没有找到它。
Json.Net 不提供特定设置来仅关闭动态类型的类型名称处理。如果您不能(或不想)用 标记相关的动态属性[JsonProperty(TypeNameHandling = TypeNameHandling.None)],那么您唯一的其他选择(除了修改 Json.Net 源代码本身)是实现自定义合同解析器以编程方式应用行为。但别担心,如果您从 Json.Net 提供的解析器之一(如DefaultContractResolver或 )派生解析器,这并不难做到CamelCasePropertyNamesContractResolver。
这是您需要的所有代码:
using System;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class OmitTypeNamesOnDynamicsResolver : DefaultContractResolver
{
public static readonly OmitTypeNamesOnDynamicsResolver Instance = new OmitTypeNamesOnDynamicsResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (member.GetCustomAttribute<System.Runtime.CompilerServices.DynamicAttribute>() != null)
{
prop.TypeNameHandling = TypeNameHandling.None;
}
return prop;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,只需将解析器添加到 中JsonSerializerSettings,您就应该全部设置好了。
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance
};
string json = JsonConvert.SerializeObject(foo, settings);
Run Code Online (Sandbox Code Playgroud)
这是一个往返演示来证明这个概念:
public class Program
{
public static void Main(string[] args)
{
Foo foo = new Foo
{
Model = new { link = "http://www.google.com", name = "John" },
Widget1 = new Doodad { Name = "Sprocket", Size = 10 },
Widget2 = new Thingy { Name = "Coil", Strength = 5 }
};
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance,
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(foo, settings);
Console.WriteLine(json);
Console.WriteLine();
Foo foo2 = JsonConvert.DeserializeObject<Foo>(json, settings);
Console.WriteLine(foo2.Model.link);
Console.WriteLine(foo2.Model.name);
Console.WriteLine(foo2.Widget1.Name + " (" + foo2.Widget1.GetType().Name + ")");
Console.WriteLine(foo2.Widget2.Name + " (" + foo2.Widget2.GetType().Name + ")");
}
}
public class Foo
{
public dynamic Model { get; set; }
public AbstractWidget Widget1 { get; set; }
public AbstractWidget Widget2 { get; set; }
}
public class AbstractWidget
{
public string Name { get; set; }
}
public class Thingy : AbstractWidget
{
public int Strength { get; set; }
}
public class Doodad : AbstractWidget
{
public int Size { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
输出:
{
"Model": {
"link": "http://www.google.com",
"name": "John"
},
"Widget1": {
"$type": "Doodad, JsonTest",
"Size": 10,
"Name": "Sprocket"
},
"Widget2": {
"$type": "Thingy, JsonTest",
"Strength": 5,
"Name": "Coil"
}
}
http://www.google.com
John
Sprocket (Doodad)
Coil (Thingy)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
855 次 |
| 最近记录: |