views:

293

answers:

9

My web application deals with strings that need to be converted to numbers alot - users often put commas, units (like cm, m, g, kg) and currency symbols in these fields so what I want to do is create a string extension method that cleans the field up and converts it to a decimal.

For example:

decimal myNumber = "15 cm".ToDecimal();
+1  A: 

Please read this article about currency implementations http://msdn.microsoft.com/en-us/goglobal/bb688126.aspx

Example:

Double myNumber = Double.Parse("$1,250.85", NumberStyles.Any);

PS. You trying parse floating point value to decimal type.

Svisstack
I think Jimbo needs to read a currency and not write it.
Oliver
This is reading the currency, and very nice, thank you - however, I would like to know how to make a string extension method anyway :P
Jimbo
@Jimbo: myNumber.ToString("C");
Svisstack
A: 

Sorry for not answering the question directly, but personally I think this could be a bad idea. Users should be told the format you expect input and, if it doesn't match that format, you should reject it and ask them to re-enter it. Otherwise you are basically trying to "second guess" what they actually meant to type and therefore run the risk of "cleaning up" the data to the extent that it's not what they actually wanted to enter. As you appear to be dealing with financial data, this is not a good thing!

Dan Diplo
Thanks, you are correct and my example was a bad one - I really just want to know how to make a string extension method :)
Jimbo
A: 

I'm with @Dan on this one.

A generic currency parser is fraught with issues. Some European users use . as thousands separator and , as decimal point, and there are other subtleties that might get in the way of an effective solution.

Consider a currency drop down/selection, a full units field and a cents field. This will make the data much less ambiguous.

spender
A: 

The most appropriate way to solve this problem seems to me to be to use the overload of Decimal.TryParse that accepts a NumberStyles and a culture. Pass it NumberStyles.Currency and an appropriate culture.

Now, there's nothing stopping you providing an extension method on string that calls this - but you do need to consider what you would like the value of d to be after

decimal d = "ponies".ToDecimal();
AakashM
Is it possible to overload `Decimal.TryParse`? Thanks
Jimbo
+1  A: 
  public static double ToDecimal(this string value)
        {
            ... your parsing magic
        }
Flo
+2  A: 

Are you expecting users of different 'cultures' to use your application? If so it's better to factor in the user's regional settings:

static decimal ToDecimal(this string str)
{
    return Decimal.Parse(str, CultureInfo.CurrentCulture);
}

Or you could replace every character in str that isn't a digit or the CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator value and then parse it as a decimal.

EDIT:
It is generally accepted that extension methods should have their own namespace. This will avoid naming conflicts and force the end user to selectively import the extensions they need.

Aside:
Extension methods can help you to write clean and elegant looking code but personally I prefer not to use them because they only seem to be half finished, a bit of a hack to get Linq working:

  • You can't create static extension methods. Do you like the String.IsNullOrEmpty method? Well you can't use that pattern in other classes. You can try but rather than having MyType.IsNullOrEmpty(myVar) you'll end up with something like myVar.IsNullOrEmpty() which leads to my next point...
  • Under normal circumstances, if myVar == null, the above code wouldn't work - it would give you a run time exception for trying to call a method on an uninstatiated object. In the case of extension methods it still works though, which leads to inconsistencies in your code. I hate inconsistencies in my code.
Phil
Thanks. It is important to note that for the above implementation, the extension method's containing STATIC CLASS must be in the same NAMESPACE as the extended class, otherwise you will have to INCLUDE the namespace in which the extension method is contained.
Jimbo
@Jimbo: Actually it is recommended that you create a seperate namespace for your extension methods and force people to import them. One reason being that extension methods can be specific to a particular business domain; not every developer will want to see every extension method, especially if you have a lot. In this case a contrived example namespace could be `namespace Extensions.Currency`.
Phil
A: 

The biggest problem is that you must know the Culture in which the user enters the number. Otherwise you will run into big problems.

A little example is the to read your number as english or german one.

In english the NumberFormatInfo.CurrencyDecimalSeparator is a dot (.) and the NumberFormatInfo.CurrencyGroupSeparator is a comma (,). In german it is exactly the other way around. So you can start wild guessing if the user means one thousand two hundred fifty or one and a fourth dollar.

Maybe you can run over all available Cultures and check if your user input contains a NumberFormatInfo.CurrencySymbol and then try the given culture. But maybe there are cultures which use the same Symbol but different Separators.

So to get this really to work you have just two really choices: * Tell your users in which culture format they have to enter their values. * Give the user the possibility to tell you which culture they decided to do.

A list of all available cultures can be get by CultureInfo.GetCultures()

Oliver
A: 

Just answering the how do I create extension method for string class:

public static class MyStringExtensions {
public static ToDecimal(this string input) {
   // ...
}
}

(and you need to have an using statement for the namespace it is located in order to use it)

mostlytech
+1  A: 

An extension method is of the following form:

public static class StringExtensions
{
    public static decimal ToDecimal(this string input)
    {
        //your conversion code here
    }
}
  • The containing class must be static. The method is also static Note the "this" keyword. I recommend the convention of grouping extension methods by the type to which they refer, but there is no requirement to do so.

Here is a guide for writing extension methods.

dpurrington