编辑: 已经将近 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
});
而且它完美地工作。
嗯,有点。
假设我有这个类(class):
public class MyClass
{
public decimal MyProp { get; set; }
}
如果我尝试反序列化这个 json:
"{\"MyProp\": 9888.77}"
当然可以,因为 9888.77
是一个 Javascript 浮点值。我想。
但是我的页面中有一个用于金钱的屏蔽输入,这使得 JSON 看起来像这样(抱歉我的英语不好):
"{\"MyProp\": \"9.888,77\" }"
AAAND,它失败了。它说 Could not convert string to decimal
。
好吧,这很公平。它不是 JS float ,但 Convert.ToDecimal("9.888,77")
以我想要的方式工作。
我在 Internet 上阅读了一些关于自定义反序列化器的教程,但是我无法为我的应用程序中的每个类定义一个自定义反序列化器。
我想要的是简单地重新定义 JSON.Net 将字符串转换为十进制属性的方式,在任何我想要反序列化的类中。当当前转换器不起作用时,我想在转换小数的过程中注入(inject) 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 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;
}
}
}
}
但它非常丑陋:它只有在崩溃时才执行我想要的,并且依赖于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();
}
}
要将其插入到您的 Binder 中,只需将转换器实例添加到 JsonSerializerSettings
对象中的 Converters
列表中:
JsonSerializerSettings settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
Formatting = Formatting.None,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
Converters = new List<JsonConverter> { new DecimalConverter() }
};
关于c# - 在 Newtonsoft.Json 中处理十进制值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24051206/