4

I need to display a currency in my ASP.NET MVC application but when the currency is 0 I would like it to display "Free" (localized of course!) instead of $0.00.

So when I have something like this...

Decimal priceFree = 0.00;
Decimal priceNotFree = 100.00;

priceFree.ToString("C");
priceNotFree.ToString("C");

The output is "$0.00" "$100.00"

I would like it to be "Free" "$100.00"

I imagine I can use the .ToString(string format, IFormatProvider formatProvider) method to accomplish this but I'm not sure how to go about it. Obvious I want to reuse as much of the NumberFormatInfo as possible and only override it when the input is 0. In that case I can simple return a localized resource that contains my "Free" string.

So how do I do this?

Thanks

Justin
  • 10,667
  • 15
  • 58
  • 79
  • 2
    I'd recommend introducing a Money/Currency class instead of passing around decimals. That would allow you to do this much more easily and because Currency has a lot more going on with it than decimals do. – Chris Missal Oct 05 '10 at 19:03

4 Answers4

17

Use

.ToString("$###.00;;Free")
Viv
  • 2,515
  • 2
  • 22
  • 26
  • 2
    +1, nice. For anyone else who hasn't seen this before: [The ";" Section Separator ](http://msdn.microsoft.com/en-us/library/0c899ak8.aspx#SectionSeparator). – Jeff Ogata Oct 05 '10 at 19:28
  • Seems interesting. Can you provide a reference or perhaps describe your answer a bit more? I'm not exactly sure whats going on there with the format string.It doesn't seem very Localization friendly. – Justin Oct 05 '10 at 19:31
  • Thanks to adrift for the reference. I like the idea but unless you can make it localization friendly I think the extension method is the way to go for this one. – Justin Oct 05 '10 at 19:42
  • 3
    @Justin: You can localize the format string, just as easily as your "free" string... (or compose it from a localized "Free" string). – Reed Copsey Oct 05 '10 at 19:57
  • Hi Reed. I do agree I could localize the rules but that requires knowledge of how other cultures localize their currency. Since this behavior is built into the framework using .ToString("C") I'd favour it. I am a fan of this particular solution its a neat one and great to have in the toolbelt! – Justin Oct 05 '10 at 23:26
4

I think the easiest way to go would be an extension method:

public static string ToPriceString(this decimal value) 
{
    if (value <= 0m) 
        return "Free"; // Your localized resource
    else 
        return value.ToString("C");
}

If you want to go with the IFormatProvider, there is a good example on MSDN.

driis
  • 161,458
  • 45
  • 265
  • 341
  • I'm not a huge fan of extension methods is my primary reason. But in this case it might be a poor excuse. Simplest solution is often the best and in this case the Extension method is very simple. – Justin Oct 05 '10 at 19:37
  • BTW: Any chance you can provide more information about value <= 0m. I'm not super family with the 0m syntax. Thanks! – Justin Oct 05 '10 at 19:49
  • Ok... so decimal explains the m. I was curious what value <= 0m would return for a negative number. But I guess in this case there is no such thing as a negative price. – Justin Oct 05 '10 at 19:54
  • 1
    Even though it represents a price, a decimal can be negative. If you used a custom class for currency instead, you could disallow that. – Chris Missal Oct 05 '10 at 21:54
2

How about an extension method:

public static string FreeString(this decimal dec)
{
   if(dec == 0M)
   {
      return "Free";
   }
   else
   {
      return dec.ToString("C");
   }
}

Then

priceFree.FreeString();
priceNotFree.FreeString();
Robaticus
  • 22,857
  • 5
  • 54
  • 63
0

Instead of using a custom IFormatProvider and passing it each time, how about this:

 public static class MyFormatter
    {
        public static string ToFreeString(this decimal d)
        {
            return d == 0 ? "Free" : d.ToString("d");
        }
    }
Aliostad
  • 80,612
  • 21
  • 160
  • 208