Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could not create an instance of type X. Type is an interface or abstract class and cannot be instantiated

Tags:

c#

json.net

Using version 7.0.1 Beta3, I'm trying to serialize/deserialize a complex POCO with properties that are arrays of abstract classes. These arrays could contain instance of classes that are derived from abstract ones.

At serialization, everything seems OK. The Json fragment below shows that the type information is set correctly.

The Json fragment:

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

But a deserialization it fails with the following error:

Could not create an instance of type QTY. Type is an interface or abstract class and cannot be instantiated.

The class hierarchy is the following :

[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
{
}

The Items property :

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

The type information in the Json fragment seems to not be used. Is this a deserialization configuration issue?

like image 872
Olivier MATROT Avatar asked May 20 '15 12:05

Olivier MATROT


2 Answers

The solution to this problem is to configure the deserializer to use the type information in the json. It is not used by default.

Serialization is done this way:

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

At deserialization, the settings for TypeNameHandling must be set:

MyDocumentType  obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MyDocumentType>(File.ReadAllText(fileName), new Newtonsoft.Json.JsonSerializerSettings 
{ 
    TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
});
like image 147
Olivier MATROT Avatar answered Sep 28 '22 07:09

Olivier MATROT


In my case, setting the TypeNameHandling to Auto didn't fix the problem, but setting it to All fixed the issue. As the TypeNameHandling = TypeNameHandling.All seemed a bit overkill to me, I chose Auto again, but this time, I passed the type of my root object to the JsonConvert.SerializeObject function as well:

var settings = new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Auto };

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

var deserializedObj = JsonConvert.DeserializeObject<ObjType>(json, settings);
like image 44
Amir Mahdi Nassiri Avatar answered Sep 28 '22 06:09

Amir Mahdi Nassiri