无法创建类型X的实例。该类型是一个接口或抽象类,无法被实例化。

52

我正在使用版本7.0.1 Beta3,尝试对一个具有抽象类数组属性的复杂POCO进行序列化/反序列化。这些数组可能包含从抽象类派生出来的类的实例。

在序列化时,一切似乎都很正常。下面的Json片段显示类型信息已正确设置。

Json片段:

 "Items": 
 [
     {
         "$type": "IVXB_TS, ...",
         "inclusive": true,
         "value": "20091231"
     }
 ]

但反序列化过程中,出现以下错误:

无法创建类型为QTY的实例。该类型是接口或抽象类,无法实例化。

类层次结构如下:

[System.Xml.Serialization.XmlIncludeAttribute(typeof(IVXB_TS))]
public abstract partial class ANY : object, System.ComponentModel.INotifyPropertyChanged
{
}

[System.Xml.Serialization.XmlIncludeAttribute(typeof(IVXB_TS))]
public abstract partial class QTY : ANY
{
}

[System.Xml.Serialization.XmlIncludeAttribute(typeof(IVXB_TS))]
public partial class TS : QTY
{
}

public partial class IVXB_TS : TS
{
}

Items属性:

[System.Xml.Serialization.XmlElementAttribute("high", typeof(IVXB_TS))]
[System.Xml.Serialization.XmlElementAttribute("low", typeof(IVXB_TS))]
public QTY[] Items

Json片段中的类型信息似乎没有被使用。这是反序列化配置问题吗?

3个回答

72

解决这个问题的方法是配置反序列化器以使用JSON中的类型信息。默认情况下不使用。

序列化是这样完成的:

Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Converters.Add(new Newtonsoft.Json.Converters.JavaScriptDateTimeConverter());
serializer.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
serializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
serializer.Formatting = Newtonsoft.Json.Formatting.Indented;

using (StreamWriter sw = new StreamWriter(fileName))
using (Newtonsoft.Json.JsonWriter writer = new Newtonsoft.Json.JsonTextWriter(sw))
{
    serializer.Serialize(writer, obj, typeof(MyDocumentType));
}

反序列化时,必须设置TypeNameHandling的设置:

MyDocumentType  obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MyDocumentType>(File.ReadAllText(fileName), new Newtonsoft.Json.JsonSerializerSettings 
{ 
    TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
});

5
这对我解决了问题。如果你要从数据库或外部数据源进行反序列化,请注意确保$type字段是你字典/JSON字符串中的第一个键。 - Ian Newland
1
请注意,将TypeNameHandling设置为除None以外的任何值,而不设置适当的SerializationBinder会导致安全漏洞:https://dev59.com/LVkS5IYBdhLWcg3wp4bO - pooya13
我们如何在不使用文件的情况下完成这个任务?只需要从对象中获取字符串即可。 - undefined

17
在我的情况下,将TypeNameHandling设置为Auto并没有解决问题,但将其设置为All则解决了这个问题。虽然TypeNameHandling = TypeNameHandling.All对我来说有点过度,但我还是选择了Auto,但这次我也传递了根对象的类型给JsonConvert.SerializeObject函数。
var settings = new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Auto };

var json = JsonConvert.SerializeObject(obj, typeof(ObjType), settings);

var deserializedObj = JsonConvert.DeserializeObject<ObjType>(json, settings);

-2

如果您指定了空值处理,就不会出现此错误。

    new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    }));

你也可以设置 [JsonIgnore] 标志

Image of the JsonIgnore flag

这两个选项对于我来说都很好用。

类型名称处理并不是必需的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接