【问题标题】:User defined struct and default (de)serialization用户定义的结构和默认(反)序列化
【发布时间】:2017-10-06 01:11:09
【问题描述】:

我定义了这个简单的类型:

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 不是答案。提前致谢。

【问题讨论】:

  • 你能提供你目前的序列化代码吗?
  • 您确定这是有效的吗?价格 = 2.3 。您不需要新建结构吗?
  • @Thangadurai 隐式运算符 public static implicit operator Price(decimal d) 负责处理

标签: c# json serialization deserialization


【解决方案1】:

现在序列化器不知道如何序列化你的结构,你需要告诉它怎么做。这是为 Json.NET 做的方法

一种方法是将JsonPropertyAttribute 添加到_value。这将导致像这样的 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。

【讨论】:

    【解决方案2】:

    您可以通过在对象上实现 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);
        }
    }
    

    【讨论】:

    • 我认为这是让它独立于库的唯一方法。
    猜你喜欢
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 1970-01-01
    相关资源
    最近更新 更多