Iva*_*nko 19 c# asp.net-mvc decimal
我试图弄清楚为什么框架拒绝将"1,234.00"值绑定到十进制.它可能是什么原因?
像"123.00"或"123.0000"这样的值绑定成功.
我有以下代码在Global.asax中设置我的文化配置
public void Application_AcquireRequestState(object sender, EventArgs e)
{
var culture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
culture.NumberFormat.NumberDecimalSeparator = culture.NumberFormat.CurrencyDecimalSeparator = culture.NumberFormat.PercentDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = culture.NumberFormat.CurrencyGroupSeparator = culture.NumberFormat.PercentGroupSeparator = ",";
Thread.CurrentThread.CurrentCulture = culture;
}
Run Code Online (Sandbox Code Playgroud)
法国文化在Web.Config中被设置为默认文化
<globalization uiCulture="fr-FR" culture="fr-FR" />
Run Code Online (Sandbox Code Playgroud)
我潜入了System.Web.Mvc.dll的ValueProviderResult类的源代码.它使用的是System.ComponentModel.DecimalConverter.
converter.ConvertFrom((ITypeDescriptorContext) null, culture, value)
Run Code Online (Sandbox Code Playgroud)
这是消息"1,234.0000不是十进制的有效值".来自.
我试图在我的操场上运行以下代码:
static void Main()
{
var decConverter = TypeDescriptor.GetConverter(typeof(decimal));
var culture = new CultureInfo("fr-FR");
culture.NumberFormat.NumberDecimalSeparator = culture.NumberFormat.CurrencyDecimalSeparator = culture.NumberFormat.PercentDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = culture.NumberFormat.CurrencyGroupSeparator = culture.NumberFormat.PercentGroupSeparator = ",";
Thread.CurrentThread.CurrentCulture = culture;
var d1 = Decimal.Parse("1,232.000");
Console.Write("{0}", d1); // prints 1234.000
var d2 = decConverter.ConvertFrom((ITypeDescriptorContext)null, culture, "1,232.000"); // throws "1,234.0000 is not a valid value for Decimal."
Console.Write("{0}", d2);
}
Run Code Online (Sandbox Code Playgroud)
DecimalConverter抛出相同的异常.Decimal.Parse正确解析相同的字符串.
Car*_*ten 14
问题是,它在调用时DecimalConverter.ConvertFrom
不支持枚举的AllowThousands
标志.好消息是,有一种方法可以"教导"它这样做!NumberStyles
Number.Parse
Decimal.Parse
内部调用Number.Parse
设置为的数字样式Number
,AllowThousands
标志设置为true.
[__DynamicallyInvokable]
public static decimal Parse(string s)
{
return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo);
}
Run Code Online (Sandbox Code Playgroud)
当您从描述符接收类型转换器时,您实际上获得了一个实例DecimalConverter
.这种ConvertFrom
方法有点普遍而且很大,所以我只引用当前场景的相关部分.缺少的部分正在实现对十六进制字符串和异常处理的支持.1
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
// ...
string text = ((string)value).Trim();
if (culture == null)
culture = CultureInfo.CurrentCulture;
NumberFormatInfo formatInfo = (NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo));
return FromString(text, formatInfo);
// ...
}
return base.ConvertFrom(context, culture, value);
}
Run Code Online (Sandbox Code Playgroud)
DecimalConverter
也覆盖了FromString
实现,问题就出现了:
internal override object FromString(string value, NumberFormatInfo formatInfo)
{
return Decimal.Parse(value, NumberStyles.Float, formatInfo);
}
Run Code Online (Sandbox Code Playgroud)
数字样式设置为Float
,AllowThousands
标志设置为false!但是,您可以使用几行代码编写自定义转换器来修复此问题.
class NumericDecimalConverter : DecimalConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
string text = ((string)value).Trim();
if (culture == null)
culture = CultureInfo.CurrentCulture;
NumberFormatInfo formatInfo = (NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo));
return Decimal.Parse(text, NumberStyles.Number, formatInfo);
}
else
{
return base.ConvertFrom(value);
}
}
}
Run Code Online (Sandbox Code Playgroud)
1 请注意,代码看起来与原始实现类似.如果您需要"未加引号"的东西,可以将其直接委托给base
您自己实施.您可以使用ILSpy/DotPeek/etc查看实现.或者从Visual Studio调试它们.
最后,在Reflection的帮助下,您可以设置类型转换器Decimal
以使用新的自定义转换器!
TypeDescriptor.AddAttributes(typeof(decimal), new TypeConverterAttribute(typeof(NumericDecimalConverter)));
Run Code Online (Sandbox Code Playgroud)