Параметр ServiceStack Text для вывода типов примитивных значений при десериализации json

У меня есть json, который генерируется во время выполнения с x количеством свойств, и по этой причине я не могу использовать POCO для его десериализации, например.

"{"UserId": 1234,"Name": "Adnan","Age": 30, "Salary": 3500.65}"

Лучший вариант для меня - десериализовать его в Dictionary<string,object>

Я использую ServiceStack JsonSerializer для десериализации json в Dictionary<string,object>, который отлично работает, но когда я пытаюсь получить типы объектов в словаре, они соответственно не совпадают.

Я пробовал следующее:

Если я не использую следующие параметры, все значения объекта словаря выводятся как strings

JsConfig.ConvertObjectTypesIntoStringDictionary = true;
JsConfig.TryToParsePrimitiveTypeValues = true;

Когда я использую вышеуказанные параметры, все значения Int64 и Double выводятся как значения Decimal.

Есть ли возможность изменить это, чтобы примитивные значения выводились как Int64 или Double вместо Decimal

Ps: у меня нет требования, чтобы он был точного типа, то есть Int32, если он попадает под эту скобку.

Я пытался использовать Json.Net, и он отлично работает, а значения объектов выводятся как Int64 и Double, но, поскольку я использую ServiceStack JsonSerializer в своем проекте, было бы неплохо узнать, как этого можно достичь с помощью этого.


person adnangohar    schedule 13.08.2014    source источник


Ответы (1)


Установить TryToParseNumericType = true

Вам нужно установить JsConfig.TryToParseNumericType = true, если вы хотите, чтобы ServiceStack.Text определял тип за пределами типа decimal.

Управление примитивными типами:

Что касается управления типами, в которые анализируются ваши числа, я представил изменения для улучшения ServiceStack.Text, чтобы обеспечить такую ​​функциональность, которая будет включена в предстоящий выпуск, с этой фиксацией.

Итак, вы сможете сделать:

JsConfig.TryParseNumericType = true;
JsConfig.ParsePrimitiveFloatingPointTypes = ParseAsType.Single;
JsConfig.ParsePrimitiveIntegerTypes = ParseAsType.Int32 | ParseAsType.Int64;

Эта конфигурация вернет Int32 вместо byte, как вы указали, это проблема. И вместо decimal вы получите float.

Для справки:

Ниже приведен обновленный метод синтаксического анализа примитивов, который теперь должен обеспечивать лучший контроль и лучшие резервные варианты, когда типы не могут быть проанализированы.

public static object ParsePrimitive(string value)
{
    if (string.IsNullOrEmpty(value)) return null;

    bool boolValue;
    if (bool.TryParse(value, out boolValue)) return boolValue;

    // Parse as decimal
    decimal decimalValue;
    var acceptDecimal = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Decimal);
    var hasDecimal = decimal.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out decimalValue);

    // Check if the number is an Primitive Integer type given that we have a decimal
    if(hasDecimal && decimalValue == decimal.Truncate(decimalValue))
    {
        // Value is a whole number
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Byte) && decimalValue <= byte.MaxValue && decimalValue >= byte.MinValue) return (byte)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.SByte) && decimalValue <= sbyte.MaxValue && decimalValue >= sbyte.MinValue) return (sbyte)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Int16) && decimalValue <= Int16.MaxValue && decimalValue >= Int16.MinValue) return (Int16)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.UInt16) && decimalValue <= UInt16.MaxValue && decimalValue >= UInt16.MinValue) return (UInt16)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Int32) && decimalValue <= Int32.MaxValue && decimalValue >= Int32.MinValue) return (Int32)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.UInt32) && decimalValue <= UInt32.MaxValue && decimalValue >= UInt32.MinValue) return (UInt32)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Int64) && decimalValue <= Int64.MaxValue && decimalValue >= Int64.MinValue) return (Int64)decimalValue;
        if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.UInt64) && decimalValue <= UInt64.MaxValue && decimalValue >= UInt64.MinValue) return (UInt64)decimalValue;
        return null;
    }

    // Value is a floating point number

    // Return a decimal if the user accepts a decimal
    if(hasDecimal && acceptDecimal)
        return decimalValue;

    // Parse as double if decimal failed or user wants a double
    double doubleValue = 0;
    var acceptDouble = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Double);
    var hasDouble = (!hasDecimal || acceptDouble) && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out doubleValue);

    // Return a double if the user accepts a double
    if(acceptDouble && hasDouble)
        return doubleValue;

    // Parse as float
    float floatValue;
    var acceptFloat = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Single);
    var hasFloat = float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatValue);

    // Return a float if the user accepts a float
    if(acceptFloat && hasFloat)
        return floatValue;

    // Default to decimal, then double , then float or null
    if(hasDecimal) return decimalValue;
    if(hasDouble) return doubleValue;
    if(hasFloat) return floatValue;
    return null;
}
person Scott    schedule 13.08.2014
comment
Спасибо, Скотт, когда я использую вышеупомянутую опцию, кажется, что она отлично работает для значений Int, но для значений Float и Double она по-прежнему выводится как Decimal. - person adnangohar; 13.08.2014
comment
@adnangohar Да, я думаю, что этот метод синтаксического анализа может быть немного ошибочным, потому что большинство строк float и double можно разобрать на decimal, но не наоборот. Так что порядок проверок здесь подводит. Я предполагаю, что это будет ошибка, которую необходимо устранить. - person Scott; 13.08.2014
comment
@adnangohar Я запросил это у команды ServiceStack. - person Scott; 13.08.2014
comment
Спасибо за помощь. Еще одна вещь, которую я заметил, заключалась в том, что если я использую "UserId": 123, он анализируется как Byte, и аналогично, когда значение int увеличивается, он начинает анализироваться с большим значением Int. Было бы хорошо, если бы у нас была какая-то настройка, в которой мы могли бы указать, что целочисленные значения должны выводиться как Int64 или Int32 и аналогично для значений Float и Double. - person adnangohar; 13.08.2014
comment
@adnangohar Я разговаривал с автором ServiceStack, и он сказал, что этот код был создан участником, в любом случае, он согласился с тем, что тестирование на числа с плавающей запятой и двойные числа должно предшествовать десятичным проверкам. Но общий консенсус заключается в том, что плавающая запятая неприятна:/ Это было исправлено в этом коммите.. - person Scott; 14.08.2014
comment
@adnangohar Я отправил запрос на включение, чтобы попытаться решить проблемы с предпочтениями типов . Если это будет принято, то можно будет указать ваши предпочтения типов. Подробнее о том, как это будет работать, в запросе на вытягивание. Не стесняйтесь комментировать там и вносить свой вклад. - person Scott; 14.08.2014
comment
спасибо за помощь и обновление. Я согласен, что с плавающей запятой сложнее обращаться. Я возьму последнюю и попробую. Обязательно внесу свой вклад в вопрос предпочтения типа. - person adnangohar; 14.08.2014
comment
@adnangohar Поступил новый запрос. В нем рассматриваются некоторые мысли, которые были у Демиса. - person Scott; 14.08.2014
comment
@adnangohar Я обновил ответ, чтобы отразить изменение, внесенное в ServiceStack.Text, которое теперь предоставляет недостающие функции, необходимые для управления возвращаемым примитивным типом. Я надеюсь, что это решит проблемы в вашем вопросе. - person Scott; 14.08.2014
comment
спасибо, я попробовал, и это работает хорошо. Если у меня возникнут какие-либо проблемы, я опубликую их по ссылке на github. - person adnangohar; 17.08.2014