NMoney for Developers

So you heard about NMoneys. You looked and the information and it caught on you. It happens that you are a .NET developer indeed. You are welcome to go on reading, but it is really not for you. You already know it.
So you have not heard of NMoneys. It does not ring any bell. It happens that you are a .NET developer indeed. You are welcome to go on reading, this is for you. It might help you answering some of all of these questions: why would you want to use it? I’d like to use, but, how?
So you have not heard of NMoneys. It does not ring any bell. It happens that you are not a .NET developer indeed. You are welcome to go on reading, but… You might enjoy the style of writing, but… We still like you, nobody’s perfect after all ;-p Please do pass the link to a developer you may know. It does not have to know .NET though. Even them have brilliant ideas ;-p

Installationv1

  • Download the binaries. I will be covering version 1 features.
  • Unpack the file to your favourite project dependencies folder
  • Add a reference from your project to NMoneys.dll (have System.Xml referenced if it is not already referenced. Fear not, no angly brackets tax to be paid)
  • Import the NMoneys namespace
  • Start writing NMoneys-enabled-awesome-codeTM

Is that it? That simple? Yes, that simple.

Working with NMoneys.Currency

First thing one can do is getting a Currency instance. Use of the “static shortcuts” provided:

Currency danishKrona = Currency.Dkk;
Currency euro = Currency.Eur;

What if your currency is different from the ones in the shortcuts? Or maybe you already have some sort of currency identifier. In those cases there are other creation methods, for example, one of the Currency.Get() overloads:

Currency canadianDollar = Currency.Get(CurrencyIsoCode.CAD),
    euro = Currency.Get("EUR"),
    swedishKrona = Currency.Get(CultureInfo.GetCultureInfo("sv-SE"));

try
{
    var rogueCurrency = Currency.Get("IAmNotAnISOCode");
}
catch (InvalidEnumArgumentException) { }

If  catching exceptions is not your favourite pastime when data is not 100% correct try using a Currency.TryGet() overload:

Currency aCurrency;
bool couldBeObtained = Currency.TryGet(CurrencyIsoCode.CAD, out aCurrency);
couldBeObtained = Currency.TryGet("EUR", out aCurrency);
couldBeObtained = Currency.TryGet(CultureInfo.GetCultureInfo("sv-SE"), outaCurrency);

bool couldNotBeObtained = Currency.TryGet("StillNotAnISOCode", outaCurrency);

One might wonder what happened to good-old constructors. Answer is that currencies are a finite set of immutable objects, being of little use the existence of different instances representing the same idea. The singleton-like behaviour was chosen over other alternatives, that is why you can’t “new-up” Currency instances. Just so you know, Currency is a reference type.

Working with NMoneys.Moneys

Having currencies and nothing else is like… well, having currencies and no monetary quantities. Let’s create those monetary quantities:

var zeroUndefinedCurrency = new Money();
var threeNoCurrencies = new Money(3m);
var twoAndAHalfAustralianDollars = new Money(2.5m, Currency.Aud);
twoAndAHalfAustralianDollars = new Money(2.5m, CurrencyIsoCode.AUD);
twoAndAHalfAustralianDollars = new Money(2.5m, "aud");
twoAndAHalfAustralianDollars = new Money(twoAndAHalfAustralianDollars);

Besides, there are some more meaningfully named creation methods:

var twoAndAHalfAustralianDollars = Money.ForCulture(2.5m, CultureInfo.GetCultureInfo("en-AU"));
var threeAndAnambientDependantCurrency = Money.ForCurrentCulture(3m);

There a quicker, more succinct  way to instantiate monetary quantities: using extension methods. Import the additional NMoneys.Extensions namespace and use those shortcuts. Ideal for unit testing scenarios:

var threeNoCurrencies = 3m.Xxx();
Money twoAndAHalfAustralianDollars = 2.5m.Aud();
twoAndAHalfAustralianDollars = 2.5m.ToMoney(CurrencyIsoCode.AUD);
twoAndAHalfAustralianDollars = 2.5m.ToMoney(Currency.Aud);
twoAndAHalfAustralianDollars = CurrencyIsoCode.AUD.ToMoney(2.5m);

Money instances can be compared and implemented comparison operands. Mind you, they have to have the same currency to be compared:

bool @true = twoPounds.CompareTo(threePounds) < 0;
@true = threePounds >= twoPounds;

object boxedThreePounds = (object) threePounds;
@true = twoPounds.CompareTo(boxedThreePounds) < 0;

try
{
    twoPounds.CompareTo(threeEuros);
}
catch (DifferentCurrencyException) { }

Value equality can be checked, as IEquatable<Money> is implemented:

bool areEqual = twoPounds.Equals(anotherTwoPounds);
areEqual = twoPounds == anotherTwoPounds;

object boxedTwoPounds = (object) anotherTwoPounds;
areEqual = twoPounds.Equals(boxedTwoPounds);

bool notEqual = twoPounds.Equals(threePounds);
notEqual = threePounds.Equals(threeEuros);
bool @true = twoPounds != threePounds;

Simple arithmetic can be performed:

Money fivePounds = twoPounds.Plus(threePounds);
Money onePound = threePounds - twoPounds;

Money youOweMeThreeEuros = -threeEuros;

Money nowIHaveThoseThreeEuros = youOweMeThreeEuros.Abs();

try
{
    twoPounds.Minus(threeEuros);
}
catch (DifferentCurrencyException) { }

More unary operations that involve the quantity:

Money twoDollars = twoAndAHalfAustralianDollars.Floor();
Money threeDollars = twoAndAHalfAustralianDollars.RoundToNearestInt(MidpointRounding.AwayFromZero);
Money twoFiftyFive = 2.553m.Aud().Round();
twoDollars = 2.559m.Aud().Truncate();
twoFiftyFive = 2.559m.Aud().TruncateToSignificantDecimalDigits();

And if the operation that you want to perform is not available, extensibility points are provided:

Money performedOnSingleInstance = 2m.Eur().Perform(amount => amount*2);
Money performedOnTwoInstances = 2m.Eur().Perform(1m.Eur(), (x, y) => -x - y);

try
{
    2m.Eur().Perform(1m.Gbp(), (_, __) => _);
}
catch (DifferentCurrencyException) { }

And last, but not least, displaying monetary quantities. This is probably, the number one Raison d’être of this library so you should be eager to see what it can do:

// default formatting, as specified by the currency "10,00 €"
10m.Dkk().ToString();

// custom format applied to currency "3.00"
3m.Usd().ToString("N");

If your country happens to share currency with other countries, but the format is not quite the same, there is a Money.ToString() overload that might come handy:

// format provider used "3,00 €", better suited for countries with same currency and different number formatting
3m.Eur().ToString(CultureInfo.GetCultureInfo("es-ES"));

For more hard-core formatting, use Money.Format():

// formatting with placeholders for currency symbol and amount "$ 03.00"
3m.Usd().Format("{1} {0:00.00}");

// rich, custom formatting "€ 1.500,00"
1500m.Eur().Format("{1} {0:#,#.00}");

And remember, Money (as opposed to Currency) is a Value Type. Amongst other things, it means it is cheap to create and small in memory footprint and it is also immutable.

What now?

If you read this far, congratulations, you are a real champ.

Secondly, you might have figured out whether this library is of any use to you. (I hope it is a yes)
Regardless the answer there are a couple of things I want to ask you:

Jolly coding

Daniel Gonzalez Garcia
Vertica A/S

Kategorier: Udvikling

Tagged as: , ,

Skriv et svar

Udfyld dine oplysninger nedenfor eller klik på et ikon for at logge ind:

WordPress.com Logo

Du kommenterer med din WordPress.com konto. Log Out / Skift )

Twitter picture

Du kommenterer med din Twitter konto. Log Out / Skift )

Facebook photo

Du kommenterer med din Facebook konto. Log Out / Skift )

Google+ photo

Du kommenterer med din Google+ konto. Log Out / Skift )

Connecting to %s