0

In my code I have to serialize List<IModel> where IModel is the interface for concrete class Model

Here is some pseudo code for them:

public interface IModel
{
    string Codice { get; set; }
    int Position { get; }
}

[DataContract]
public class Model : IModel
{
    public Model(string Codice, int position)
    {
        this.Codice = Codice;
        this.position = position;

    }
    [DataMember(Name = "codice")]
    public string Codice { get; set; }
    [DataMember(Name = "position")]
    int position;
    public int Position { get { return position; } }
}

After reading this post I wrote:

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List<IModel>), new[] { typeof(Model) });
using (FileStream writer = File.Create(@"c:\temp\modello.json"))
        {
            jsonSerializer.WriteObject(writer, myList);
        }

It works but it is ugly and the output contains a field for the type of the element, "__type":"Model:#SomeProjectName". Is there another way to easily serialize a list when it is declared as List<InterfaceName> while it contains elements of the only concrete class that implement that interface ? I tried with some casts but I got compilation error or runtime exceptions.

I would like to specify that in my previous implementation I copied all items from List<IModel> into List<Model> which was the type known to DataContractJsonSerializer. In fact I'm sure that any IModel is a Model.

dbc
  • 104,963
  • 20
  • 228
  • 340
Filippo
  • 1,123
  • 1
  • 11
  • 28
  • Why not serializing the concrete class? What is the purpose to use the interface in this case? – Ben Jul 25 '17 at 11:23
  • maybe try this: https://stackoverflow.com/questions/8513042/json-net-serialize-deserialize-derived-types – Jodn Jul 25 '17 at 11:37
  • @Ben The interface was created to have a layer of abstraction and now all the code uses that interface instead of the implementing class. At the moment it was written it seemed a good idea, now it is there but it is not strictly necessary – Filippo Jul 25 '17 at 13:07
  • And what was wrong with your previous implementation? I just want to understand your thoughts :) – Ben Jul 25 '17 at 13:35

2 Answers2

0

Why do you need an interface for any such implementation? I would suggest you to generate C# classes for your JSON through http://json2csharp.com/. Once done , paste those classes and find the <RootObject> class and then serialize it using the code you mentioned in your question

Apoorv
  • 2,023
  • 1
  • 19
  • 42
0

Here is a solution with AutoMapper. I've changed your implemented class by adding a private setter to Position. I hope this is OK for your.

List<IModel> sourceList = new List<IModel> {new Model("A", 1), new Model("B", 2)};

AutoMapper.Mapper.Initialize(a => a.CreateMap<IModel, Model>());
List<Model> targetList = AutoMapper.Mapper.Map<List<IModel>, List<Model>>(sourceList);

AutoMapper.Mapper.Initialize(a =>
{
    a.CreateMap<Model, Model>();
    a.CreateMap<Model, IModel>().ConstructUsing(Mapper.Map<Model, Model>);
});

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List<Model>), new[] { typeof(Model) });
using (FileStream writer = File.Create(@"c:\temp\modello.json"))
{
    jsonSerializer.WriteObject(writer, targetList);
}

DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(List<Model>));
MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(File.ReadAllText(@"c:\temp\modello.json")));
List<Model> targetListFromFile = (List<Model>)js.ReadObject(ms);
List<IModel> sourceListFromFile = AutoMapper.Mapper.Map<List<Model>, List<IModel>>(targetListFromFile);

Interface:

public interface IModel
{
    string Codice { get; set; }
    int Position { get; }
}

Class:

[DataContract]
public class Model : IModel
{
    public Model(string Codice, int position)
    {
        this.Codice = Codice;
        Position = position;
    }

    [DataMember(Name = "codice")]
    public string Codice { get; set; }
    [DataMember(Name = "position")]
    public int Position { get; private set; }
}

The file looks like this:

[{
    "codice": "A",
    "position": 1
},
{
    "codice": "B",
    "position": 2
}]
Ben
  • 763
  • 1
  • 5
  • 14