将json序列化为一个具有catch all字典属性的对象。

13 浏览
0 Comments

将json序列化为一个具有catch all字典属性的对象。

我想使用JSON.net将数据反序列化为一个对象,但是将未映射的属性放在一个字典属性中。这个可能吗?

例如给定json,

{one:1,two:2,three:3}

和C#类:

public class Mapped {
   public int One {get; set;}
   public int Two {get; set;}
   public Dictionary TheRest {get; set;}
}

JSON.NET能够反序列化为一个实例,其值为one=1,two=1,TheRest=Dictionary{{"three,3"}}吗?

0
0 Comments

问题的出现原因:

在将JSON数据反序列化为对象时,有时会遇到一些额外的属性,这些属性在对象中没有对应的属性。然而,我们仍然希望能够将这些额外的属性保存下来,并在需要的时候进行处理。但是,传统的反序列化方式无法处理这种情况,因为它要求JSON数据中的每个属性都要有对应的对象属性。

解决方法:

使用JsonExtensionData属性来定义一个“捕获所有”字典是解决这个问题的最简单方法。通过使用这个属性,我们可以将额外的属性保存在一个字典中,并在需要的时候进行处理。

在示例代码中,定义了一个名为DirectoryAccount的类,并使用JsonExtensionData属性定义了一个名为_additionalData的字典属性。在反序列化时,如果JSON数据中有任何没有对应属性的额外属性,这些属性将被添加到_additionalData字典中。在OnDeserialized方法中,可以对_additionalData字典进行处理,提取出需要的属性值,然后赋值给对应的对象属性。

通过这种方式,我们可以灵活地处理任何额外的属性,而不需要在类中定义对应的属性。

示例代码中的JSON数据如下:

{
  'DisplayName': 'John Smith',
  'SAMAccountName': 'contoso\\johns'
}

通过使用JsonConvert.DeserializeObject方法,将JSON数据反序列化为DirectoryAccount对象,并可以通过对象的属性访问对应的值。

最后,通过以下代码输出对象的属性值:

Console.WriteLine(account.DisplayName);
// John Smith
Console.WriteLine(account.Domain);
// contoso
Console.WriteLine(account.UserName);
// johns

通过上述的解决方法,我们可以方便地处理JSON数据中的额外属性,并将其保存下来以供后续处理。

0
0 Comments

问题的出现原因:用户想要将JSON序列化为对象,并且希望将所有的属性都放在一个字典中。

解决方法:可以创建一个CustomCreationConverter来实现这个需求。下面是一个示例代码,演示了如何实现这个功能。首先定义了一个Mapped类,其中包含了一个私有的字典属性_theRest,以及一些其他的属性。然后创建了一个MappedConverter类来继承CustomCreationConverter,并重写了Create和ReadJson方法。在ReadJson方法中,首先通过反射获取Mapped类的所有属性名,并将其转换为小写。然后在循环中,通过判断reader的TokenType是否为PropertyName来获取属性名,并将其转换为小写。然后通过判断属性名是否存在于objProps中来判断是否是Mapped类的属性。如果是,则通过反射获取属性的类型,并将reader的值转换为对应的类型,然后通过反射设置属性的值。如果不是,则将属性名和reader的值添加到_theRest字典中。最后返回mappedObj对象。在Main方法中,通过调用JsonConvert.DeserializeObject方法来将JSON字符串反序列化为Mapped对象,并传入MappedConverter作为参数。然后可以通过mappedObj.TheRest来获取字典中的值。

这样,将JSON序列化为对象后,mappedObj对象的输出结果将是一个具有One和Two属性的对象,而其他所有属性都被放在字典中。这里只是将One和Two属性硬编码为int类型,但这只是演示如何实现的一种方式。

希望这可以帮到你。代码已经更新,使其更加通用。尽管没有完全测试,但我认为它可以基本满足你的需求。如果你希望更加通用,可能需要使用一些反射。但基本结构不会改变,只是在第二个if(reader.Read())块中的逻辑会有所变化。希望你能理解我的意思。顺便说一下,你提出的问题非常有趣。

代码已经更新,使其更加通用,可以处理不同的属性名和/或类型。

0