I have the same class in two projects one is being sent on runtime
to the other process that has to de-serialize that object and use it (giving that the two objects are the same but differ in assembly name so they are actually interpreted as two different types). From my research i have came with those solutions that doesn't work for the following reasons.
Json.NET
: giving me an exceptions that the two types aren't compatible (tried using typename.all in serialization settings).
protobuf-net
: requires me to add attributes every where or simply provide it with the properties name (in v2), which both aren't possible for me due to the fact that my object is too complex.
BinaryFormatter
: same reasons as protobuf-> tons of attributes.
Use Common Assembly
: For some reasons related to the architecture of my project i can't.
So is there any simple way to serialize one type then de-serializing it to another type (which is virtually the same class but in different assembly) ?
Yes, it is absolutely possible to serialize using classes in one assembly and deserialize into classes of another assembly using Json.Net. In fact, that is one of the main use cases for serialization in the first place -- transmitting data between different systems.
There are two things you need to keep in mind:
- If your source and target assemblies are different, then you should not include the actual fully-qualified type names as metadata in the JSON. In other words, make sure that the
TypeNameHandling
setting is set toNone
(which I believe is the default). If you include the type name metadata, then Json.Net will expect to find those assemblies on the receiving side, and the deserialization will fail because those assemblies are not there. - If you are using interfaces in your class structure instead of concrete types then you will need to create one or more
JsonConverter
classes to handle the deserialization. When Json.Net sees an interface it will not know what type of concrete class to create, because it could be anything. A converter can look for other data that might be present in the JSON and tell Json.Net which concrete class to instantiate. If there is no obvious piece of data in the JSON that can be used as an indicator for the type, you can use a converter on the serialization side to add a custom indicator.
Here is some example code to demonstrate the concepts I've laid out. The demo is broken into two parts. The first part is the "sender", which serializes a made-up "diagram" class structure to JSON and writes it to a file. The second part is the "receiver", which reads the file and deserializes the JSON into a different set of classes. You'll notice I've intentionally made some of the class names in the receiver different than the sender, but they have the same property names and structure, so it still works. You'll also notice that the receiver program uses a custom JsonConverter
to handle creating the correct IFigure
instances using the presence of certain properties in the JSON as indicators.
Sender
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace Sender
{
class Program
{
static void Main(string[] args)
{
Diagram diagram = new Diagram
{
Title = "Flowchart",
Shapes = new List<IShape>
{
new Circle
{
Id = 1,
Text = "Foo",
Center = new Point { X = 1, Y = 5 },
Radius = 1.25
},
new Line
{
Id = 2,
A = new Point { X = 2.25, Y = 5 },
B = new Point { X = 4, Y = 5 }
},
new Rectangle
{
Id = 3,
Text = "Bar",
TopLeft = new Point { X = 4, Y = 6.5 },
BottomRight = new Point { X = 8.5, Y = 3.5 }
}
}
};
string json = JsonConvert.SerializeObject(diagram, Formatting.Indented);
File.WriteAllText(@"C:\temp\test.json", json);
}
}
class Diagram
{
public string Title { get; set; }
public List<IShape> Shapes { get; set; }
}
interface IShape
{
int Id { get; set; }
string Text { get; set; }
}
abstract class AbstractShape : IShape
{
public int Id { get; set; }
public string Text { get; set; }
}
class Line : AbstractShape
{
public Point A { get; set; }
public Point B { get; set; }
}
class Rectangle : AbstractShape
{
public Point TopLeft { get; set; }
public Point BottomRight { get; set; }
}
class Circle : AbstractShape
{
public Point Center { get; set; }
public double Radius { get; set; }
}
class Point
{
public double X { get; set; }
public double Y { get; set; }
}
}
Here is the JSON output file generated by the Sender program:
{
"Title": "Flowchart",
"Shapes": [
{
"Center": {
"X": 1.0,
"Y": 5.0
},
"Radius": 1.25,
"Id": 1,
"Text": "Foo"
},
{
"A": {
"X": 2.25,
"Y": 5.0
},
"B": {
"X": 4.0,
"Y": 5.0
},
"Id": 2,
"Text": null
},
{
"TopLeft": {
"X": 4.0,
"Y": 6.5
},
"BottomRight": {
"X": 8.5,
"Y": 3.5
},
"Id": 3,
"Text": "Bar"
}
]
}
Receiver
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Receiver
{
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText(@"C:\temp\test.json");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new FigureConverter());
Chart chart = JsonConvert.DeserializeObject<Chart>(json, settings);
Console.WriteLine(chart);
Console.ReadKey();
}
}
class FigureConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IFigure));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo["Center"] != null)
{
return jo.ToObject<Circle>(serializer);
}
else if (jo["TopLeft"] != null)
{
return jo.ToObject<Rectangle>(serializer);
}
else
{
return jo.ToObject<Line>(serializer);
}
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
class Chart
{
public string Title { get; set; }
public List<IFigure> Shapes { get; set; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("Chart: ");
sb.AppendLine(Title);
foreach (IFigure figure in Shapes)
{
sb.AppendLine(figure.ToString());
}
return sb.ToString();
}
}
interface IFigure
{
int Id { get; set; }
string Text { get; set; }
}
abstract class AbstractFigure : IFigure
{
public int Id { get; set; }
public string Text { get; set; }
}
class Line : AbstractFigure
{
public Point A { get; set; }
public Point B { get; set; }
public override string ToString()
{
return string.Format("Line: A = {0}, B = {1}", A, B);
}
}
class Rectangle : AbstractFigure
{
public Point TopLeft { get; set; }
public Point BottomRight { get; set; }
public override string ToString()
{
return string.Format("Rectangle: TopLeft = {0}, BottomRight = {1}", TopLeft, BottomRight);
}
}
class Circle : AbstractFigure
{
public Point Center { get; set; }
public double Radius { get; set; }
public override string ToString()
{
return string.Format("Circle: Center = {0}, Radius = {1}", Center, Radius);
}
}
class Point
{
public double X { get; set; }
public double Y { get; set; }
public override string ToString()
{
return string.Format("({0:0.##}, {1:0.##})", X, Y);
}
}
}
Here is the output of the Receiver program:
Chart: Flowchart
Circle: Center = (1, 5), Radius = 1.25
Line: A = (2.25, 5), B = (4, 5)
Rectangle: TopLeft = (4, 6.5), BottomRight = (8.5, 3.5)
来源:https://stackoverflow.com/questions/28509591/serialize-in-one-assembly-and-de-serialize-in-another