ServiceStack文本设置,用于在反序列化json时推断原始值类型

时间:2014-08-13 15:47:03

标签: servicestack jsonserializer servicestack-text

我有一个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;

当我使用上述选项时,所有Int64Double值都会被推断为Decimal值。

是否有任何更改此选项的选项,以便将原始值推断为Int64Double而不是Decimal

Ps:我并不要求它必须是确切的类型,即如果它属于该括号,则为Int32

我尝试过使用Json.Net并且工作正常,对象值推断为Int64Double,但我在项目中使用ServiceStack JsonSerializer会很好要知道如何使用它来实现这一目标。

1 个答案:

答案 0 :(得分:2)

设置TryToParseNumericType = true

如果您希望ServiceStack.Text确定超出JsConfig.TryToParseNumericType = true类型的类型,则需要设置decimal

控制基元类型:

关于控制解析数字的类型,我提交了更改以改进ServiceStack.Text,以提供将在即将发布的版本with this commit中包含的此类功能。

所以你可以这样做:

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