User-defined structure and standard (de) serialization

I have this simple type:

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 deserialize the given JSON to Price

, it works fine. But when I try to serialize it returns empty { }

. I mean, let's say this model:

public class Product {
    public string Name { get; set; }
    public Price Price { get; set; }
}

      

deserializng JSON like this:

{ "Name": "Some name", "Price": 2.3 }

      

gives me the correct object. But let's serialize 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 the serializer libraries (like Json.NET and Jil) how to serialize my custom types?

UPDATE:

Sample serialization code using Json.NET

var s = JsonConvert.SerializeObject(p);

      

UPDATE2: I don't want to depend on Json.NET or any other third party libs. So use JsonConverter

in Json.NET is not the answer. Thanks in advance.

+3


source to share


2 answers


Now the serializer doesn't know how to serialize your structure and you need to be told how to do it. Here's how to do it for Json.NET

One way is to add JsonPropertyAttribute

to _value

. This will cause the json to be

{"Name":"Some Name","Price":{"_value":2.3}}

      

Another way is to create your own JsonConverter that will treat your price as decimal. A simplified approach might 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 JsonConverterAttribute

in your structure

[JsonConverter(typeof(PriceConverter))]
struct Price
{
    //...
}

      

This will give you json like this

{"Name":"Some Name","Price":2.3}

      

Both methods serialize and deserialize just fine, but the second makes it nicer to read json.

+3


source


You can customize the serialization process by implementing the ISerializable interface on an object. This is especially useful in cases where the value of a member variable is invalid after deserialization, but you need to supply the variable with a value to restore the full state of the object. ISerializable implementation involves injecting the GetObjectData method and a custom 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);
    }
}

      

+1


source







All Articles