在不修改类的情况下省略动态属性的类型?

时间:2016-09-08 08:33:48

标签: c# .net json serialization json.net

我有一堆域对象,我将其序列化,发送到其他应用程序,然后使用Json.Net进行反序列化。这些对象可能具有

属性
  • 定义为具有多个派生类的抽象基类
  • 动态属性

我使用了TypeNameHandling.Auto,它将$type属性添加到与声明的类型不同的类型。但是,此设置对我的动态属性有不必要的副作用,即它们的类型也会被声明。

在下面的示例中,model是我的C#代码中定义为public dynamic Model { get; set; }的动态属性。

"model":{"$type":"<>f__AnonymousType0`3[[System.String, mscorlib],[System.String, mscorlib],[System.String, mscorlib]], ExampleAssembly","link":"http://www.google.com","name":"John"}

当尝试在另一个程序集中反序列化此字符串时,Json.Net不能(当然)找到ExampleAssembly。使用TypeNameHandling.None属性提供以下属性序列化

"model": {"link":"http://www.google.com","name":"John"}

可以成功反序列化为dynamic。但是,这会破坏派生类型的反序列化。

有关如何在不实施自定义IContractResolver和其他自定义代码的情况下实现此功能的任何想法?

我不拥有域对象,所以我不能用属性装饰它们或它们的属性或者允许它们实现接口等。我正在寻找的是序列化器中的某种设置,它省略了类型dynamics

恕我直言,这应该可以通过设置以某种方式进行配置,我只是没有找到它。

1 个答案:

答案 0 :(得分:4)

Json.Net不提供特定设置来仅关闭动态类型的类型名称处理。如果您不能(或者不想)使用$(document).ready(function(){ $('#a-div').show(); $('#b-div').hide(); $('#c-div').hide(); $('#a-btn').click(function(){ $('#b-div').hide(); $('#c-div').hide(); $('#a-div').show(); }); $('#b-btn').click(function(){ $('#a-div').hide(); $('#c-div').hide(); $('#b-div').show(); }); $('#c-btn').click(function(){ $('#a-div').hide(); $('#b-div').hide(); $('#c-div').show(); }); }); 标记相关的动态属性,那么您唯一的其他选择(缺少修改Json.Net源代码本身)就是实现自定义合同解析程序以编程方式应用该行为。但是不用担心,如果您从Json.Net提供的解析器(例如[JsonProperty(TypeNameHandling = TypeNameHandling.None)]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; } } ,您应该全部设置。

JsonSerializerSettings

这是一个证明这个概念的往返演示:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance
};

string json = JsonConvert.SerializeObject(foo, settings);

输出:

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; }
}