如何在C#中使用属性控制属性的序列化

时间:2019-06-01 17:59:11

标签: c# serialization attributes deserialization

我想控制特定类如何序列化其数据...例如:

    [TimeSeriesSerialization(TimeSeriesSerializationType.Dates)]
    public TimeSeries DailyValues { get; set; }

    [TimeSeriesSerialization(TimeSeriesSerializationType.Normal)]
    public TimeSeries IntraDayValues { get; set; }

在这里的示例中,我有一个名为TimeSeries的类,该类具有一个DateTimes列表和一个十进制列表...当我对其进行序列化时,我想做两件事...创建一个JSON字符串,它是一组时间/值对...例如:

{"2018-01-30T09:30:01":9958.2289,"2018-01-30T09:30:02":9958.2284,...}

但是我也希望可以选择将此类序列化为Date值(没有时间)...如此:

{"2018-01-30":9958.2289,"2018-01-31":9958.2284,...}

或仅作为值:

[9958.2289,9958.2284,...]

有帮助吗?

public enum TimeSeriesSerializationType
{
    Times,
    Dates,
    ValuesOnly,
}

public class TimeSeries
{
    public List<DateTime> Times = new List<DateTime>();
    public List<decimal> Values = new List<decimal>();

    public void Add(DateTime time, decimal value)
    {
        Times.Add(time);
        Values.Add(value);
    }

    public string Serialize(TimeSeriesSerializationType timeSeriesSerializationType)
    {
        switch (timeSeriesSerializationType)
        {
            case TimeSeriesSerializationType.Dates:
                {
                    var data = new Dictionary<DateTime, decimal>();
                    for (var i = 0; i < Times.Count; i++)
                    {
                        if (!data.ContainsKey(Times[i])) // duplicate dates???
                            data.Add(Times[i], Values[i]);
                    }
                    var isoDateTimeConverter = new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd" };
                    var json = JsonConvert.SerializeObject(data, Formatting.None, isoDateTimeConverter);
                    return json;
                }
            case TimeSeriesSerializationType.ValuesOnly:
                {
                    var json = JsonConvert.SerializeObject(Values, Formatting.None);
                    return json;
                }
            default:
                {
                    var data = new Dictionary<DateTime, decimal>();
                    for (var i = 0; i < Times.Count; i++)
                    {
                        if (!data.ContainsKey(Times[i])) // duplicate times???
                            data.Add(Times[i], Values[i]);
                    }
                    var isoDateTimeConverter = new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz" };
                    var json = JsonConvert.SerializeObject(data, Formatting.None, isoDateTimeConverter);
                    return json;
                }
        }
    }

    public void Deserialize(string str)
    {
        if (string.IsNullOrEmpty(str)) return;
        var data = JsonConvert.DeserializeObject<Dictionary<DateTime, decimal>>(str);
        if (data.Count <= 0) return;
        foreach (var d in data)
            this.Add(d.Key, d.Value);
    }
}

2 个答案:

答案 0 :(得分:0)

我认为您已经拥有了大部分所需的东西。
缺少的是属性本身。

您可以这样定义它(您可以阅读有关AttributeUsage-Attribute here的更多信息):

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
class TimeSeriesSerializationAttribute : Attribute
{
    public TimeSeriesSerializationType SerializationType { get; }

    public TimeSeriesSerializationAttribute(TimeSeriesSerializationType timeSeriesSerializationType)
    {
        SerializationType = timeSeriesSerializationType;
    }
}

现在,您可以像写过一样在属性上方添加这些属性。

评估部分的时间。您可以使用类似的方法读取所有属性,并使用它们来序列化您的TimeSeries。
顺便说一句,如果您获得的属性结果为null,则不会设置该属性。您可以完全跳过该属性,也可以使用默认的SerializationType,无论您是否需要。

public static void SerializeToSomewhere(YourClassWithTimeSeries instance) {
    // get all public, instance properties 
    IEnumerable<PropertyInfo> allProps = typeof(YourClassWithTimeSeries).GetProperties(BindingFlags.Public | BindingFlags.Instance);
    // only take TimeSeries-properties
    IEnumerable<PropertyInfo> timeSeriesProps = allProps.Where(p => p.PropertyType == typeof(TimeSeries));

    foreach (PropertyInfo property in timeSeriesProps)
    {
        // get the attribute
        TimeSeriesSerializationAttribute attribute = property.GetCustomAttribute<TimeSeriesSerializationAttribute>();
        if (attribute == null) continue; // or do something else like use a default SerializationType

        // get the value
        TimeSeries value = (TimeSeries)property.GetValue(instance, null);

        // serialize using the type from the attribute
        string serializedValue = value.Serialize(attribute.SerializationType);
        // Do whatever with the serialized value (for example save it to a file or whatever)
    }
}

希望这对您有所帮助。如果您需要其他信息,也有很多属性教程和文档。我还将尝试回答您可能有的问题,请随时提出。

编辑:
小东西要添加。在您的代码中,TimeSeries类公开了公共字段“时间和值”。你不应该那样做。 而不是这样做:

public List<DateTime> Times = new List<DateTime>();
public List<decimal> Values = new List<decimal>();

您应该这样做。这样可以防止您不小心从班级内部或外部再次分配它。

public List<DateTime> Times { get; } = new List<DateTime>();
public List<decimal> Values { get; } = new List<decimal>();

答案 1 :(得分:0)

更行人但有效的方法(对于json)...

    [JsonIgnore]
    public PriceSeries DailyValues { get; set; }
    [JsonProperty(PropertyName = "DailyValues")]
    public string DailyValuesSerialized {
        get
        {
            return (DailyValues == null) ?
                null : 
                DailyValues.Serialize(TimeSeriesSerializationType.ValuesOnly);
        }
        set
        {
            DailyValues = (value == null) ? null : new PriceSeries(value);
        }
    }

    [JsonIgnore]
    public PriceSeries IntraDayValues { get; set; }
    [JsonProperty(PropertyName = "IntraDayValues")]
    public string IntraDayValuesSerialized
    {
        get
        {
            return (IntraDayValues == null) ?
                null : 
                IntraDayValues.Serialize(TimeSeriesSerializationType.Normal);
        }
        set
        {
            IntraDayValues = (value == null) ? null : new PriceSeries(value);
        }
    }

或者这个(对于数据库)...

    [NotMapped]
    public PriceSeries DailyValues { get; set; }
    [Column("DailyValues")]
    public string DailyValuesSerialized
    {
        get
        {
            return (DailyValues == null) ?
                null :
                DailyValues.Serialize(TimeSeriesSerializationType.ValuesOnly);
        }
        set
        {
            DailyValues = (value == null) ? null : new PriceSeries(value);
        }
    }

    [NotMapped]
    public PriceSeries IntraDayValues { get; set; }
    [Column("IntraDayValues")]
    public string IntraDayValuesSerialized
    {
        get
        {
            return (IntraDayValues == null) ?
                null :
                IntraDayValues.Serialize(TimeSeriesSerializationType.Normal);
        }
        set
        {
            IntraDayValues = (value == null) ? null : new PriceSeries(value);
        }
    }