用户自定义结构体和默认(反)序列化

5

我有一个简单的类型定义:

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

当我将给定的JSON反序列化为Price时,它可以正常工作。但是当我尝试进行序列化时,它返回一个空的{ }。我的意思是,假设有这个模型:

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

反序列化这样的 JSON:

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

给我正确的对象。但是对于这个示例进行序列化:

var p = new Product { Name = "Some name", Price = 2.3 }

创建这个JSON:
{ "Name": "Some name", "Price": { } }

那么,我应该如何告诉序列化库(例如Json.NET和Jil),如何序列化我的自定义类型?以下是示例序列化代码,使用的是Json.NET。
var s = JsonConvert.SerializeObject(p);

更新2: 我不希望依赖于Json.NET或任何其他第三方库。因此,在Json.NET中使用JsonConverter不是答案。提前感谢。


你能提供你当前的序列化代码吗? - Manprit Singh Sahota
你确定这是有效的吗?Price = 2.3。难道你不需要创建新的结构体吗? - Thangadurai
1
@Thangadurai 隐式操作符 public static implicit operator Price(decimal d) 负责处理此事。 - sm_
2个回答

7

现在,序列化程序不知道如何序列化您的结构体,您需要告诉它如何执行。以下是在Json.NET中执行此操作的方法:

一种方法是向_value添加JsonPropertyAttribute。这将导致类似于以下的json输出:

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

另一种方法是创建自己的JsonConverter来将您的价格视为十进制数。一个简单的方法可能看起来像这样:
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));
    }
}

你需要在你的结构体上使用JsonConverterAttribute

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

这将会给你返回如下格式的JSON数据。
{"Name":"Some Name","Price":2.3}

这两种方式都可以成功地进行序列化和反序列化,但第二种方式会创建更易于阅读的json格式。


1
你可以通过在对象上实现ISerializable接口来自定义序列化过程。在反序列化后,如果成员变量的值无效,但需要为变量提供一个值以重构对象的完整状态,则此方法特别有用。实现ISerializable涉及实现GetObjectData方法和一个特殊的构造函数,在对象反序列化时将使用该构造函数。
下面的示例代码显示了如何实现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);
    }
}

我认为这是实现独立于库的唯一方法。 - Mats391

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接