Search code examples
c#serializationdeserialization

Serialize type to an arbitrary string


I've declared a struct TaxpayerIdentificationNumber, that contains private long and represents 13 digits. I want to be able to serialize it into a mere string, that contains that private number (padded with zeros in front, but never mind it).

For example, we have DateTime, that serializes to "2020-01-01T00.00.01" and not to "{'ticks': 34546 }". I want that special treatment for my types too. And deserialization from a simple string as well.

I've explored ISerialized and its associated method and constructor, but didn't eventually understand, how to just define the method, which will form the final string I want.


Solution

  • It looks like you're doing JSON serialization; so, something like this, assuming you're using Newtonsoft.Json?

    using Newtonsoft.Json;
    using System;
    
    var obj = new HazFoo { Value = new("whatever") };
    var json = JsonConvert.SerializeObject(obj); // {"Value":"whatever"}
    Console.WriteLine(json);
    var clone = JsonConvert.DeserializeObject<HazFoo>(json);
    Console.WriteLine(clone.Value.TaxpayerIdentificationNumber); // whatever
    
    class HazFoo
    {
        public Foo Value { get; set; }
    }
    
    [JsonConverter(typeof(FooConverter))]
    readonly struct Foo : IEquatable<Foo>
    {
        public string TaxpayerIdentificationNumber { get; }
    
        public Foo(string id) => TaxpayerIdentificationNumber = id;
    
        private sealed class FooConverter : JsonConverter<Foo>
        {
            public override Foo ReadJson(JsonReader reader, Type objectType, Foo existingValue, bool hasExistingValue, JsonSerializer serializer)
                => new Foo((string)reader.Value);
    
            public override void WriteJson(JsonWriter writer, Foo value, JsonSerializer serializer)
                => writer.WriteValue(value.TaxpayerIdentificationNumber);
        }
    
        // these have nothing to do with serialization, but are good practice
        // for value-types, to avoid unnecessary boxing
        public override bool Equals([NotNullWhen(true)] object obj)
            => obj is Foo other && Equals(other);
        public override int GetHashCode()
            => TaxpayerIdentificationNumber?.GetHashCode() ?? 0;
        public override string ToString()
            => TaxpayerIdentificationNumber;
        public bool Equals(Foo other)
            => TaxpayerIdentificationNumber == other.TaxpayerIdentificationNumber;
    }