Пользовательский Json.net JsonConverter с предупреждением Конструктора "Для этого объекта не определен конструктор без параметров" - PullRequest
1 голос
/ 17 мая 2019

Когда я использую newtosoft.json в netcore 2.1, я сталкиваюсь с проблемой. когда Я добавляю конструктор в мой класс ApiErrorConverter, который наследуется от JsonConverter. Это предупреждает меня

«Для этого объекта не определен беспараметрический конструктор».

Когда я удаляю конструктор из моего ApiErrorConverter класса, он будет хорошо работать Но я хочу передать некоторое значение в JsonConverter реализовать преобразование карты JSON в объект C # гибко. Вот мой код:

string payload2 ={\"statusCode\":123,\"name\":\"error_code\",\"description\":\"The Message\",\"item\":{\"ahah\":\"cl\"}}


public class ApiErrorConverter : JsonConverter
{
    Dictionary<string, string> _propertyMappings = new Dictionary<string,
    string>();
    public ApiErrorConverter(Dictionary<string, string> dataparam)
    {
        propertyMappings = dataparam;
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value,
    JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    public override bool CanConvert(Type objectType)
    {
        return objectType.GetTypeInfo().IsClass;
    }
    public override object ReadJson(JsonReader reader, Type objectType,
    object existingValue, JsonSerializer serializer)
    {
        object instance = Activator.CreateInstance(objectType);
        var props = objectType.GetTypeInfo().DeclaredProperties.ToList();

        JObject jo = JObject.Load(reader);
        foreach (JProperty jp in jo.Properties())
        {
            if (!_propertyMappings.TryGetValue(jp.Name, out var name))
                name = jp.Name;
            PropertyInfo prop = props.FirstOrDefault(pi =>
            pi.CanWrite &&
            pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);
            prop.SetValue(instance, jp.Value.ToObject(prop.PropertyType,
            serializer));
        }
        return instance;
    }
}


static void Main(string[] args)
{
    Dictionary<string, string> test = new Dictionary<string, string>
{
{"name", "error"},
{"code", "errorCode"},
{"description", "message"}
};
    var apiError2 = JsonConvert.DeserializeObject<ApiError>(payload2, new ApiErrorConverter(test));
}


public class ApiError
{
    [JsonProperty("error")]
    public string Error { get; set; }
    [JsonProperty("errorCode")]
    public string ErrorCode { get; set; }
    [JsonProperty("message")]
    public string Message { get; set; }
    [JsonProperty("statusCode")]
    public int StatusCode { get; set; }
}

В любом случае, я просто хочу преобразовать карту JSON в объект C #. Как я могу передать словарь в ApiErrorConverter без этой ошибки?

Как можно сопоставить объект json с C # с помощью newtosoft.json гибко, как я пытаюсь сделать?

1 Ответ

1 голос
/ 17 мая 2019

Проблема не в том, что ваш ApiErrorConverter имеет конструктор, а в том, как вы вызываете значение свойства json для метода объекта. Поскольку вы передаете сериализатор, он снова вызывает метод ReadJson для свойства. Это терпит неудачу во втором свойстве (строке), поскольку строка не имеет конструктора без параметров. Если вы используете перегрузку ToObject, которая просто указывает тип, она будет работать. Учитывая предоставленный образец данных, вам также нужно проверить NULL в PropertyInfo перед его использованием.

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    object instance = Activator.CreateInstance(objectType);
    var props = objectType.GetTypeInfo().DeclaredProperties.ToList();

    JObject jo = JObject.Load(reader);
    foreach (JProperty jp in jo.Properties())
    {
        if (!_propertyMappings.TryGetValue(jp.Name, out var name))
            name = jp.Name;
        PropertyInfo prop = props.FirstOrDefault(pi =>
        pi.CanWrite &&
        pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);
        prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType));
    }
    return instance;
}

Ответ на дополнительные комментарии:

Был задан вопрос, учитывая другую структуру json:

string payload2 = "{\"statusCode\":123,\"code\":\"error_code\",\"name\":\"hahaha\",\"description\":\"The Message\",\"qqqitem\":[{\"ahah\":\"cl\",\"ahahah\":\"item\"}]}";

Как получить массив с именем qqqitem в мой десериализованный объект?

Во-первых, массив - это объект с двумя свойствами: ахах и ахахах, для этого нам нужно создать класс. Я назову это Item.

public class Item
{
    public string ahah { get; set; }

    public string ahahah { get; set; }
}

Тогда нам нужно, чтобы наш класс ApiError содержал массив этих объектов. Я создам его в виде списка.

public class ApiError
{
    [JsonProperty("error")]
    public string Error { get; set; }

    [JsonProperty("errorCode")]
    public string ErrorCode { get; set; }

    [JsonProperty("message")]
    public string Message { get; set; }

    [JsonProperty("statusCode")]
    public int StatusCode { get; set; }

    [JsonProperty("items")]
    public List<Item> Items { get; set; }
}

Наконец, поскольку имена не совпадают, я добавлю отображение

Dictionary<string, string> test = new Dictionary<string, string>
{
    {"name", "error"},
    {"code", "errorCode"},
    {"description", "message"},
    {"qqqitem", "items"}
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...