Deserializing Class with 2 non-default constructors

One option is to have a different class just for serialisation. Then map to your original, either manually or using AutoMapper.

As a bonus you will find your business object is then free to be refactored without worrying about what that does to the serialisation. Because you are right it shouldn't know about json.

Replace public constructors with static methods

Another option is to reduce the number of constructors, I try not to have more than one, often having none (by which I mean no public constructors).

Example:

public Isbn(int groupCode, int publisherCode, int titleCode, int checkCode)
{
    _groupCode = groupCode;
    _publisherCode = publisherCode;
    _titleCode = titleCode;
    _checkCode = checkCode;
}

public static Isbn FromString(string isbn)
{
    if (isbn == null)
        throw new ArgumentNullException("isbn");
    if (isbn == "") return;
    if (!IsValid(isbn)) return;
    var isbnStrings = isbn.Split(new[] {'-', ' '}, StringSplitOptions.RemoveEmptyEntries);
    var groupCode = Convert.ToInt32(isbnStrings[0]);
    var publisherCode = Convert.ToInt32(isbnStrings[1]);
    var titleCode = Convert.ToInt32(isbnStrings[2]);
    var checkCode = Convert.ToInt32(isbnStrings[3]);
    return new Isbn(groupCode, publisherCode, titleCode, checkCode);
}

I think this answer is a little bit late but someone may want to use it.

You can do it by creating a custom JsonConverter

public class IsbnConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Isbn);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject)
        {
            var dict = new Dictionary<string, int>();
            serializer.Populate(reader, dict);
            return new Isbn(dict["groupCode"], dict["publisherCode"], dict["titleCode"], dict["checkCode"]);
        }

        if (reader.TokenType == JsonToken.String)
        {
            return new Isbn((string)reader.Value);
        }

        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

The only thing you need is to pass this Converter to JsonConvert.DeserializeObject

var yourobj = JsonConvert.DeserializeObject<T>(json, new IsbnConverter());

Now deserializetion can work for both json's

{ .... , isbn:{groupCode:1,publisherCode:2,titleCode:3,checkCode:4}, ...... }
{ .... , isbn:"1-2-3-4", .... }

For ex;

public class Book
{
    public string Title { get; set; }
    public Isbn isbn { get; set; }
}

string json1 = @"{Title:""Title 1"", isbn:{groupCode:1,publisherCode:2,titleCode:3,checkCode:4}}";
string json2 = @"{Title:""Title 2"", isbn:""1-2-3-4""}";

var book1 = JsonConvert.DeserializeObject<Book>(json1, new IsbnConverter());
var book2 = JsonConvert.DeserializeObject<Book>(json2, new IsbnConverter());

Tags:

C#

Json