使用2个非默认构造函数反序列化Class

时间:2014-06-27 07:40:47

标签: c# json

我有一个班级,使用Json.net

为使用它的对象提供服务。
public class JsonSerializer
{
    public string Serialize(object toSerialaze)
    {
        return JsonConvert.SerializeObject(toSerialaze);
    }

    public T Deserialize<T>(string toDeserialaze)
    {
        return JsonConvert.DeserializeObject<T>(toDeserialaze);
    }
}

并向它提供这样一个类的对象

 public class Isbn
    {
        private readonly int _groupCode;
        private readonly int _publisherCode;
        private readonly int _titleCode;
        private readonly int _checkCode;
        private static readonly Regex Regex = new Regex(@"^\s*\d*\s*-\s*\d*\s*-\s*\d*\s*-\s*\d*\s*$");

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

        public Isbn(string isbn)
        {
            if (isbn == null)
                throw new ArgumentNullException("isbn");
            if (isbn == "") return;
            if (!IsValid(isbn)) return;
            var isbnStrings = isbn.Split(new[] {'-', ' '}, StringSplitOptions.RemoveEmptyEntries);
            _groupCode = Convert.ToInt32(isbnStrings[0]);
            _publisherCode = Convert.ToInt32(isbnStrings[1]);
            _titleCode = Convert.ToInt32(isbnStrings[2]);
            _checkCode = Convert.ToInt32(isbnStrings[3]);
        }
    }

我得到一个例外:     其他信息:无法找到用于类型Library.Isbn的构造函数。一个类应该有一个默认的构造函数,一个带参数的构造函数或一个用JsonConstructor属性标记的构造函数。 我知道,我可能会在反序列化时将[JsonConstructor]放在我需要使用的构造函数之前,但我不希望类Isbn知道Json。 我怎么能以另一种方式做同样的事情?我怎样才能让JsonConverter知道,使用哪两个构造函数?

2 个答案:

答案 0 :(得分:2)

一种选择是为序列化设置一个不同的类。然后手动或使用AutoMapper映射到原始文件。

作为奖励,您会发现您的业务对象可以自由重构,而不必担心序列化会对此产生什么影响。因为你是对的,所以不应该知道json。

使用静态方法替换公共构造函数

另一个选择是减少构造函数的数量,我尽量不要多于一个,通常没有(我的意思是没有公共构造函数)。

示例:

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

答案 1 :(得分:2)

我认为这个答案有点晚,但有人可能想要使用它。

您可以通过创建自定义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();
    }
}

您唯一需要的是将此转换为JsonConvert.DeserializeObject

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

现在反序列化可以适用于json的两个

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

对于前任;

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