Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Newtonsoft.Json中处理十进制值_C#_Javascript_Json_Json.net_Deserialization - Fatal编程技术网

C# 在Newtonsoft.Json中处理十进制值

C# 在Newtonsoft.Json中处理十进制值,c#,javascript,json,json.net,deserialization,C#,Javascript,Json,Json.net,Deserialization,编辑:已经快5年了,我不认为这是应该走的路。客户应以正确的数字格式发布数据。对于当前的框架,如React或Angular,或者具有适当的体系结构和错误处理与验证,我认为这几乎不是问题 但是,如果有人想展示他们的Json.NET肌肉,请随意查看答案 我有一个MVC应用程序,我在其中处理一些JSON。这很简单。我的ModelBinder中有一段简单的代码: return JsonConvert.DeserializeObject(jsonString, bindingContext.ModelTy

编辑:已经快5年了,我不认为这是应该走的路。客户应以正确的数字格式发布数据。对于当前的框架,如React或Angular,或者具有适当的体系结构和错误处理与验证,我认为这几乎不是问题

但是,如果有人想展示他们的Json.NET肌肉,请随意查看答案


我有一个MVC应用程序,我在其中处理一些JSON。这很简单。我的ModelBinder中有一段简单的代码:

return JsonConvert.DeserializeObject(jsonString, bindingContext.ModelType, new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    MissingMemberHandling = MissingMemberHandling.Ignore,
    Formatting = Formatting.None,
    DateFormatHandling = DateFormatHandling.IsoDateFormat,
    FloatParseHandling = FloatParseHandling.Decimal
});
而且它工作得完美无瑕

嗯,有点

假设我有一门课:

public class MyClass
{
    public decimal MyProp { get; set; }
}
public class DecimalReader : JsonTextReader
{
    public DecimalReader(string s)
        : base(new StringReader(s))
    {
    }

    public override decimal? ReadAsDecimal()
    {
        try
        {
            return base.ReadAsDecimal();
        }
        catch (Exception)
        {
            if (this.TokenType == JsonToken.String)
            {
                decimal value = 0;

                bool convertible = Decimal.TryParse(this.Value.ToString(), out value);

                if (convertible)
                {
                    return new Nullable<decimal>(value);
                }
                else { throw; }
            }
            else
            {
                throw;
            }
        }
    }
}
如果我尝试反序列化此json:

"{\"MyProp\": 9888.77}"
当然可以,因为
9888.77
是一个Javascript浮点值。我想

但是我的页面中有一个隐藏的金钱输入,使JSON看起来像这样(对不起我的英语):

而且,它失败了。它说它
无法将字符串转换为十进制

好的,这很公平。它不是JS浮点,而是
Convert.ToDecimal(“9.888,77”)
以我想要的方式工作

我在互联网上读过一些关于自定义反序列化程序的教程,但是为应用程序中的每个类定义自定义反序列化程序对我来说是不可侵犯的

我想要的是简单地重新定义JSON.Net将字符串转换为十进制属性的方式,在我想要反序列化到的任何类中。当电流转换器不工作时,我想在转换小数的过程中插入
Convert.ToDecimal
函数

有什么办法我可以做到吗

我认为有办法做到这一点,所以我稍微修改了我的代码

JsonSerializer serializer = new JsonSerializer
{
    NullValueHandling = NullValueHandling.Ignore,
    MissingMemberHandling = MissingMemberHandling.Ignore,
    Formatting = Formatting.None,
    DateFormatHandling = DateFormatHandling.IsoDateFormat,
    FloatParseHandling = FloatParseHandling.Decimal,
};



return serializer.Deserialize(new DecimalReader(jsonStr), bindingContext.ModelType);
创建了这个类:

public class MyClass
{
    public decimal MyProp { get; set; }
}
public class DecimalReader : JsonTextReader
{
    public DecimalReader(string s)
        : base(new StringReader(s))
    {
    }

    public override decimal? ReadAsDecimal()
    {
        try
        {
            return base.ReadAsDecimal();
        }
        catch (Exception)
        {
            if (this.TokenType == JsonToken.String)
            {
                decimal value = 0;

                bool convertible = Decimal.TryParse(this.Value.ToString(), out value);

                if (convertible)
                {
                    return new Nullable<decimal>(value);
                }
                else { throw; }
            }
            else
            {
                throw;
            }
        }
    }
}
公共类小数读取器:JsonTextReader
{
公共小数读取器(字符串s)
:底座(新的StringReader)
{
}
公共重写十进制?ReadAsDecimal()
{
尝试
{
返回base.ReadAsDecimal();
}
捕获(例外)
{
if(this.TokenType==JsonToken.String)
{
十进制值=0;
bool convertible=Decimal.TryParse(this.Value.ToString(),out Value);
if(可兑换)
{
返回新的可为空(值);
}
else{throw;}
}
其他的
{
投掷;
}
}
}
}
但是它非常丑陋:它只在崩溃时执行我想要的,并且依赖于
base.ReadAsDecimal()
崩溃。再难看不过了

并且不起作用
将值“1.231,23”转换为类型“System.Nullable1[System.Decimal]”时出错。路径“MyProp”,第X行,位置Y.

值本身正在转换,但可能出于某种原因,它仍试图将字符串“1.231,23”转换为十进制


那么,有没有一种方法可以正确执行呢?

您可以使用这样一个自定义的
JsonConverter
类来处理这两种格式(JSON数字表示和屏蔽字符串格式)

class DecimalConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(decimal) || objectType == typeof(decimal?));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Float || token.Type == JTokenType.Integer)
        {
            return token.ToObject<decimal>();
        }
        if (token.Type == JTokenType.String)
        {
            // customize this to suit your needs
            return Decimal.Parse(token.ToString(), 
                   System.Globalization.CultureInfo.GetCultureInfo("es-ES"));
        }
        if (token.Type == JTokenType.Null && objectType == typeof(decimal?))
        {
            return null;
        }
        throw new JsonSerializationException("Unexpected token type: " + 
                                              token.Type.ToString());
    }

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

太多了!我一直在寻找一种解决方案,使小数总是以类似的方式序列化,这篇文章给了我正确的方向。这是我的代码:

    internal class DecimalConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(decimal) || objectType == typeof(decimal?));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            Decimal? d = default(Decimal?);
            if (value != null)
            {
                d = value as Decimal?;
                if (d.HasValue) // If value was a decimal?, then this is possible
                {
                    d = new Decimal?(new Decimal(Decimal.ToDouble(d.Value))); // The ToDouble-conversion removes all unnessecary precision
                }
            }
            JToken.FromObject(d).WriteTo(writer);
        }
    }

作为对Kwaazaar答案的扩展,我还向转换器添加了相反的方式(在他的示例中,它抛出了一个
NotImplementedException

namespace Something.Converter
{
使用制度;
使用Newtonsoft.Json;
使用Newtonsoft.Json.Linq;
/// 
/// 
///将对象转换为JSON或从JSON转换为JSON。
/// 
/// 
公共类小数转换器:JsonConverter
{
/// 
///获取的新实例。
/// 
公共静态只读DecimalConverter实例=新DecimalConverter();
/// 
/// 
///确定此实例是否可以转换指定的对象类型。
/// 
///对象的类型。
/// 
///如果此实例可以转换指定的对象类型,则为true;否则为false。
/// 
/// 
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(decimal)| objectType==typeof(decimal?);
}
/// 
/// 
///读取对象的JSON表示形式。
/// 
///这本书是用来阅读的。
///对象的类型。
///正在读取的对象的现有值。
///调用序列化程序。
///对象值。
/// 
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
如果(!(reader.Value是字符串值))
{
if(objectType==typeof(decimal?)
{
返回null;
}
返回默认值(十进制);
}
//ReSharper禁用一次StyleCop.SA1126
if(十进制色数(值,输出变量结果))
{
//ReSharper禁用一次StyleCop.SA1126
返回结果;
}
if(objectType==typeof(decimal?)
{
返回null;
}
返回默认值(十进制);
}
/// 
/// 
///写入对象的JSON表示形式。
/// 
///要写信给的人。
///价值。
///调用序列化程序。
/// 
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
var d=默认值(十进制?);
if(值!=null)
{
d=十进制数值?;
if(d.HasValue)
{
d=新的十进制数(十进制数。ToDouble(d.值));
}
}
JToken.FromObject(d??0).Wr