I have this simple type defined:
public struct Price : IComparer<Price>, IEquatable<Price> {
private readonly decimal _value;
public Price(Price value) {
_value = value._value;
}
public Price(decimal value) {
_value = value;
}
public int Compare(Price x, Price y) {
return x._value.CompareTo(y._value);
}
public int Compare(Price x, decimal y) {
return x._value.CompareTo(y);
}
public int Compare(decimal x, Price y) {
return x.CompareTo(y._value);
}
public bool Equals(Price other) {
return _value.Equals(other._value);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj))
return false;
return obj is Price && Equals((Price)obj);
}
public override int GetHashCode() {
return _value.GetHashCode();
}
public static implicit operator decimal(Price p) {
return p._value;
}
public static implicit operator Price(decimal d) {
return new Price(d);
}
}
When I'm deserializing a given JSON to Price
it works just fine. But when I'm trying to serialize, it returns an empty { }
. I mean, assume having this model:
public class Product {
public string Name { get; set; }
public Price Price { get; set; }
}
deserializng a JSON like this:
{ "Name": "Some name", "Price": 2.3 }
gives me the correct object. But serializing this sample:
var p = new Product { Name = "Some name", Price = 2.3 }
creates this json:
{ "Name": "Some name", "Price": { } }
So, how and what can I do to tell serializer libraries (e.g. Json.NET and Jil) how to serialize my custom types?
UPDATE:
Sample serializing code, using Json.NET
var s = JsonConvert.SerializeObject(p);
UPDATE2:
I dont want to be depend on Json.NET or any other thirdparty libs. So, using JsonConverter
in Json.NET is not the answer. Thanks in advance.
Right now the serializer does not know how to serialize your struct and you need to tell it how to do it. This is how to do it for Json.NET
One way is to add JsonPropertyAttribute
to _value
. That would result in json like this
{"Name":"Some Name","Price":{"_value":2.3}}
Another way would be to create your own JsonConverter that treats your price as a decimal. A simplistic approach could look like this
class PriceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof( decimal? );
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize( reader ) as Price?;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize( writer, (decimal)((Price)value));
}
}
And you will need the JsonConverterAttribute
on your struct
[JsonConverter(typeof(PriceConverter))]
struct Price
{
//...
}
This will give you json like this
{"Name":"Some Name","Price":2.3}
Both ways serialize and deserialize fine, but the second one creates nicer to read json.
You can customize the serialization process by implementing the ISerializable interface on an object. This is particularly useful in cases where the value of a member variable is invalid after deserialization, but you need to provide the variable with a value in order to reconstruct the full state of the object. Implementing ISerializable involves implementing the GetObjectData method and a special constructor that will be used when the object is deserialized.
The sample code below shows how to implement ISerializable.
public struct Price : IComparer<Price>, IEquatable<Price>, ISerializable
{
private readonly decimal _value;
public Price(Price value)
{
_value = value._value;
}
public Price(decimal value)
{
_value = value;
}
public int Compare(Price x, Price y)
{
return x._value.CompareTo(y._value);
}
public int Compare(Price x, decimal y)
{
return x._value.CompareTo(y);
}
public int Compare(decimal x, Price y)
{
return x.CompareTo(y._value);
}
public bool Equals(Price other)
{
return _value.Equals(other._value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
return obj is Price && Equals((Price)obj);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Value", _value);
}
public static implicit operator decimal(Price p)
{
return p._value;
}
public static implicit operator Price(decimal d)
{
return new Price(d);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With