- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一些继承,需要自定义 JsonConverter
进行反序列化。我现在使用一种非常直接的方法,根据某些属性的存在来确定类型。
重要说明:在我的实际代码中,我无法触及DeserializeObject
调用,即我无法在那里添加自定义转换器。我知道这在某种程度上是一个 XY 问题,因此我意识到我的回答可能是我想要的是不可能的。据我所知,这使我的问题与 this question 略有不同。 .
这是我的情况的重现:
abstract class Mammal { }
class Cat : Mammal { public int Lives { get; set; } }
class Dog : Mammal { public bool Drools { get; set; } }
class Person
{
[JsonConverter(typeof(PetConverter))]
public Mammal FavoritePet { get; set; }
[JsonConverter(typeof(PetConverter))]
public List<Mammal> OtherPets { get; set; }
}
这是自定义转换器:
public class PetConverter : JsonConverter
{
public override bool CanConvert(Type objectType) { return objectType == typeof(Mammal); }
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
JObject jsonObject = JObject.Load(reader);
if (jsonObject["Lives"] != null) return jsonObject.ToObject<Cat>(serializer);
if (jsonObject["Drools"] != null) return jsonObject.ToObject<Dog>(serializer);
return null;
}
}
这对 FavoritePet
很有效,但对 OtherPets
就没那么好了,因为它是一个列表。下面是使用 NUnit 测试重现我的问题的方法:
[TestFixture]
class MyTests
{
[Test]
public void CanSerializeAndDeserializeSingleItem()
{
var person = new Person { FavoritePet = new Cat { Lives = 9 } };
var json = JsonConvert.SerializeObject(person);
var actual = JsonConvert.DeserializeObject<Person>(json);
Assert.That(actual.FavoritePet, Is.InstanceOf<Cat>());
}
[Test]
public void CanSerializeAndDeserializeList()
{
var person = new Person { OtherPets = new List<Mammal> { new Cat { Lives = 9 } } };
var json = JsonConvert.SerializeObject(person);
var actual = JsonConvert.DeserializeObject<Person>(json);
Assert.That(actual.OtherPets.Single(), Is.InstanceOf<Cat>());
}
}
后一个测试是红色的,因为:
Newtonsoft.Json.JsonReaderException : Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path 'OtherPets', line 1, position 33.
我也尝试过在 OtherPets
上不使用自定义转换器,结果是:
Newtonsoft.Json.JsonSerializationException : Could not create an instance of type JsonConverterLists.Mammal. Type is an interface or abstract class and cannot be instantiated. Path 'OtherPets[0].Lives', line 1, position 42.
我明白发生了什么,我什至知道我可以修复它:
var actual = JsonConvert.DeserializeObject<Person>(json, new PetConverter());
但重复上面的注释:我无法更改 DeserializeObject
调用,因为它被包装在我目前无法更改的库中的函数中。
有没有办法用基于属性的方法来做同样的事情,例如是否有一个内置的列表转换器,其中每个条目都包含一个自定义转换器?还是我也必须为此推出自己的单独转换器?
脚注,如何重现:
安装包 Newtonsoft.Json -Version 7.0.1
安装包 nunit -版本 2.6.4
您可以将以上三个代码块放入您的新命名空间并运行 NUnit 测试,看到第二个代码块失败。
最佳答案
稍微调整了转换器类。希望一切顺利 -
public class PetConverter : JsonConverter
{
public override bool CanConvert(Type objectType) { return objectType == typeof(Mammal); }
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
if (reader.TokenType == JsonToken.StartArray)
{
var li = new List<Mammal>();
var arr = JArray.Load(reader);
foreach (JObject obj in arr)
{
if (obj["Drools"] != null)
{
var k = obj.ToObject<Dog>(serializer);
li.Add(k);
}
}
return li;
}
JObject jsonObject = JObject.Load(reader);
if (jsonObject["Lives"] != null) return jsonObject.ToObject<Cat>(serializer);
//if (jsonObject["Drools"] != null) return jsonObject.ToObject<Dog>(serializer);
return null;
}
}
关于c# - 如何在不将转换器传递给 DeserializeObject 的情况下反序列化抽象项列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35309559/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!