【发布时间】:2018-02-02 03:20:15
【问题描述】:
我在实现 IFormatProvider 类时遇到了一些麻烦,该类可以将包含百分比的字符串解析为等效的数字。
问题不在于解析。 Stackoverflow 提供了几种解决方案来将包含百分比的字符串解析为数字。
- One solution involves creating a new number type called Percentage,
- Other solutions do not respect different cultures, or create a new TypeConverter
我宁愿不实现新类型。恕我直言,百分比不是一种新类型,它只是显示数字的一种不同方式。百分号就像小数点。在某些文化中,这是一个点,在其他文化中,这是一个逗号。这也不会导致不同的类型,只会导致不同的字符串格式。
函数Double.Parse(string, IformatProvider)(等)提供了解析字符串的可能性,与标准的 Double.Parse 稍有不同。
我的问题出在IFormatProvider。可以订购Parse 函数以使用特殊的IFormatProvider。但是我不能给这个IFormatProvider 任何功能来做特殊的解析。 (顺便说一句:格式化为字符串几乎可以正常工作)。
MSDN describes the functionality of an IFormatProvider:
IFormatProvider 接口提供一个对象,该对象为格式化和解析操作提供格式化信息。 ... 典型的解析方法是 Parse 和 TryParse。
默认的IFormatProvider 不包含Parse(意思是函数Parse,不是动词解析)字符串,其中包含System.Globalization.NumberFormatInfo 中提到的百分比格式
所以我想,也许我可以创建自己的IFormatProvider,它使用本问题第一行中提到的解决方案,以便根据提供的NumberFormatInfo 解析百分比,例如每种类型都有 Parse 函数将字符串解析为数字。
用法如下:
string txt = ... // might contain a percentage
// convert to double:
IFormatProvider percentFormatProvider = new PercentFormatProvider(...)
double d = Double.Parse(percentageTxt, percentFormatProvider)
我尝试过的 (这是第一个要求的)
所以我创建了一个简单的IFormatProvider 并检查如果我用IFormatProvider 调用Double.Parse 会发生什么
class PercentParseProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
...
}
}
调用使用:
string txt = "0.25%";
IFormatProvider percentParseProvider = new PercentParseProvider();
double d = Double.Parse(txt, percentParseProvider);
确实,GetFormat 被调用,请求 NumberFormatInfo 类型的对象
NumberFormatInfo 类已密封。因此,如果需要更改属性值,我只能返回标准NumberFormatInfo。但是我不能返回提供特殊解析方法来解析百分比的派生类
String.Format(IFormatProvider, string, args)
我注意到,在转换为字符串时使用格式提供程序进行特殊格式化,对于String.Format 效果很好。在这种情况下,GetFormat 被称为请求ICustomFormatter。您所要做的就是返回一个实现ICustomFormatter 的对象并在ICustomFormatter.Format 中进行特殊格式化。
这按预期工作。返回 ICustomFormatter 后,调用它的 ICustomFormat.Format,我可以在其中进行我想要的格式化。
Double.ToString(IFormatProvider)
但是,当我使用Double.ToString(string, IFormatProvider) 时,我遇到了与Parse 相同的问题。在GetFormat 中要求密封NumberFormatInfo。如果我返回一个ICustomFormatter,那么返回的值将被忽略并使用默认的NumberFormatInfo。
结论:
- String.Format(...) 可以与 IFormatProvider 很好地配合使用,如果需要,您可以进行自己的格式化
- Double.ToString(...) 需要一个密封的 NumberFormatInfo,您不能自己进行格式化
- Double.Parse 需要一个密封的 NumberFormatInfo。不允许自定义解析。
那么:如何在 IFormatProvider 中提供 MSDN 承诺的解析?
【问题讨论】:
-
对于
IFormatProvider,Double支持NumberFormatInfo和CultureInfo(但仅限于NumberFormat的CultureInfo)。在找出允许的数字样式后,它将解析委托给一个讨厌的不安全方法,该方法无疑已根据作者的最佳能力进行了优化。这就是代码,这就是它所允许的全部。您不能使用完全自定义的IFormatProvider来解析和格式化双精度数,至少不能通过Double.[Try]Parse。 -
结论 MSDN 声明:IFormatProvider 接口提供了一个对象,该对象为...解析操作提供格式信息,似乎没有完全实现,对于 String.Format 与 Double.ToString 也不同
-
MSDN 说对象“提供格式化信息”并没有错。这与承诺您可以完全挂钩解析不同(实际上您不能)。公平地说,这是 .NET 1.0 中的一种设计,它并不是最引人注目的(
GetFormat返回一个object,真的吗?) -
好吧,杰罗恩,你是对的。 GetFormat 必须能够返回 ICustomFormatters 以及 NumberFormatInfo 以及 DateTimeFormatInfo,因此返回 Object。但你说得有道理。最好是返回带有函数 Format 和 Parse 接口的对象
标签: c# parsing iformatprovider