I have some trouble implementing an IFormatProvider class that can parse strings that contain percentages into their numeric equivalent.
The problem is not in the parsing. Stackoverflow provides several solutions to parse a string that contains a percentages into a number.
- One solution involves creating a new number type called Percentage,
- Other solutions do not respect different cultures, or create a new TypeConverter
I'd rather not implement a new type. IMHO a percentage is not a new type, it is just a different way of displaying a number. A percentage sign is like the decimal point. In some cultures this is a dot, in other cultures this is a comma. This also does not lead to different types, only to different string formatting.
The functions Double.Parse(string, IformatProvider) (et al), provide possibilities to parse strings slightly different than the standard Double.Parse would do.
The problem I have is in the IFormatProvider
. It is possible to order the Parse
functions to use a special IFormatProvider
. However I can't give this IFormatProvider
any functionality to do special parsing. (By the way: Formatting to strings works almost fine).
MSDN describes the functionality of an IFormatProvider:
The IFormatProvider interface supplies an object that provides formatting information for formatting and parsing operations. ... Typical parsing methods are Parse and TryParse.
The default IFormatProvider
does not Parse
(meaning the function Parse
, not the verb parse) strings that contains the percentage format as mentioned in System.Globalization.NumberFormatInfo
So I thought, maybe I could create my own IFormatProvider
, that uses the solutions mentioned in the first lines of this question in such a way that it can be used to parse percentages according to the provided NumberFormatInfo
, for every type that has Parse
functions to parse strings into numbers.
Usage would be:
string txt = ... // might contain a percentage
// convert to double:
IFormatProvider percentFormatProvider = new PercentFormatProvider(...)
double d = Double.Parse(percentageTxt, percentFormatProvider)
What I've tried (that's the first what's being asked for)
So I created a simple IFormatProvider
and checked what happened if I would call Double.Parse
with the IFormatProvider
class PercentParseProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
...
}
}
Called using:
string txt = "0.25%";
IFormatProvider percentParseProvider = new PercentParseProvider();
double d = Double.Parse(txt, percentParseProvider);
And indeed, GetFormat
is called, asking for an object of type NumberFormatInfo
Class NumberFormatInfo
is sealed. So I can only return a standard NumberFormatInfo
, if needed with changed values for properties. But I can't return a derived class that provides a special parsing method to parse percentages
String.Format(IFormatProvider, string, args)
I've noticed that using a format provider to do special formatting when converting to strings, works fine for String.Format
. In that case GetFormat
is called asking for an ICustomFormatter. All you have to do is return an object that implements ICustomFormatter
and do the special formatting in ICustomFormatter.Format.
This works as expected. After returning the ICustomFormatter, its ICustomFormat.Format is called, where I can do the formatting I want.
Double.ToString(IFormatProvider)
However, when I used Double.ToString(string, IFormatProvider) I ran into the same problems as with Parse
. In GetFormat
a sealed NumberFormatInfo
is asked for. If I return an ICustomFormatter
, then the returned value is ignored and the default NumberFormatInfo
is used.
Conclusion:
- String.Format(...) works fine with IFormatProvider, If desired you can do your own formatting
- Double.ToString(...) expects a sealed NumberFormatInfo, you can't do your own formatting
- Double.Parse expects a sealed NumberFormatInfo. No custom parsing allowed.
So: how to provide the parsing that MSDN promises in IFormatProvider?