28

When going from a double to a decimal, presuming my double can be represented as a decimal...

Is it more appropriate to cast a double as a decimal:
(Explicit Numeric Conversions Table) (Note that this entry erroneously contradicts the former!)

double foo = bar;
decimal foobar = (decimal)foo;

Or is it more appropriate to call the decimal constructor:
(Decimal Constructor)

double foo = bar;
decimal foobar = new decimal(foo);

I tend to use the decimal constructor, but I wonder reasons to use one versus the other.

From what I can tell the only difference is that an explicit cast of a double below Decimal.MinValue returns a zero, while using the constructor throws an OverflowException

EDIT: @Joren in the comments below notes that the cast throws an OverflowException for small values as well... so apparently the MSDN documentation is incorrect.

Related Questions:
- C# cast a double variable to decimal
- Automatically cast from double to decimal safely: Is the following safe?

Community
  • 1
  • 1
Matthew
  • 10,244
  • 5
  • 49
  • 104
  • 2
    Would it not even be safer to do: decimal foobar = Convert.ToDecimal(foo); http://msdn.microsoft.com/en-us/library/h5aa2331.aspx – Daniel Casserly Nov 23 '11 at 20:36
  • @DanielCasserly Considering that conversion has the same behavior as the constructor I would contend that either the constructor makes that call or is already more efficient. – Matthew Nov 23 '11 at 20:40
  • 3
    @DanielCasserly It has the same semantics as `new decimal(double)`. In fact, it might *not* be "safer", because `Convert.ToDecimal(object)` might be selected if we bumbled the object being passed in for some reason. –  Nov 23 '11 at 20:41
  • Thanks, that's useful to know. :-) – Daniel Casserly Nov 23 '11 at 20:41
  • FWIW, I cast. double to float. long to int. so, likewise, double to decimal -- of course, as pointed out, it's quite possible to introduce "quiet" errors in violation of "fail fast", if that is what is ascribed to. –  Nov 23 '11 at 20:44
  • Why did somebody vote to close? – Matthew Nov 23 '11 at 20:51
  • 2
    "From what I can tell the only difference is that an explicit cast of a double below Decimal.MinValue returns a zero, while using the constructor throws an OverflowException" I can't reproduce this difference. Casting always gives me an overflow exception, both in release and debug builds, and both in unchecked and checked contexts. Does anyone know what the standard says? – Joren Nov 23 '11 at 20:52
  • @Joren that is interesting. I suppose then that the MSDN documentation is incorrect! – Matthew Nov 23 '11 at 20:52

5 Answers5

18

There's really no difference. Using ILSpy:

// decimal
public static explicit operator decimal(double value)
{
    return new decimal(value);
}

Based on examining the IL with LINQPad, the operator overload is called the same way in checked and unchecked contexts in C#.

In Visual Basic, CDec([double]) and CType([double],Decimal) calls the constructor directly, so there's no difference in that regard, but the cast is more able to participate in compile-time constant-folding than the constructor.

Random832
  • 37,415
  • 3
  • 44
  • 63
12

I would rather go for the constructor then! At least you get informed that your value is out of limits instead of setting it to 0 silently! The documentation says:

The explicit numeric conversion may cause loss of precision or result in throwing exceptions.

If one does not really care about precision than casting can be used. In the other hand, if you are playing with money for example, the last thing you would do is rounding off doubles! You don't want your application to turn valuable decimal fractions to 0 where you do not expect it to do so.

GETah
  • 20,922
  • 7
  • 61
  • 103
  • Well... presuming that the developer knows the behaviors of each... In my case I know that the `double` *can be* represented as a `decimal` – Matthew Nov 23 '11 at 20:41
  • @MatthewPK That is actually true. I don't really see a good reason behind this design decision. – GETah Nov 23 '11 at 20:44
  • 1
    To your edit: If I'm working with money then I shouldn't be using doubles anyhow. – Matthew Nov 23 '11 at 20:58
  • @Matthew True. It was just an example :) – GETah Nov 23 '11 at 20:59
  • 1
    @GETah: Conversions from `double` to `Decimal` are inherently lossy. For example, while the `double` quantity 1.0/3.0 is within about 19 parts per 10^18 of being correct, conversion of the aforementioned `double` to `Decimal` yields a value which is off by 333 parts per 10^18. Such loss occurs even though `Decimal` can represent values far more precisely than `double`; 1.0m/3.0m is evaluated to within 0.000000000003 parts per 10^18. BTW, even some integral values which are precisely representable as `double` lose precision when cast to `Decimal`. – supercat Dec 10 '12 at 20:28
5

Edit: See Joren's comment on the main post. This will still throw an exception here in LINQPad 4 (C#4/.NET4) even when unchecked.


Another option is to use checked (assuming an unchecked context otherwise):

double d = double.MaxValue;
decimal f = checked((decimal)d);

Which results in:

OverflowException: Value was either too large or too small for a Decimal.

In the end of the day, however, I think this question is "not a real question" in that which approach is used depends not primarily on the [expected] inputs, but rather, what should happen on an overflow.

Happy coding.

  • In light of the MSDN docs error and the identical behavior of the two methods then I contend that this is a "best practice" question. – Matthew Nov 23 '11 at 20:56
3

I would use the constructor, because that conversion could potentially produce unexpected results due to the difference in precision. It seems logical that the constructor is more prepared to handle the conversion.

As noted in your question there are some circumstances where conversion from double to decimal will result in an OverflowException, which may require some special handling in your code. Casting ignores this exception, which may not be desirable if precision is critical.

http://msdn.microsoft.com/en-us/library/9sc2bx9h.aspx

James Johnson
  • 45,496
  • 8
  • 73
  • 110
  • Per MSDN, casting can lead to exceptions just as the constructor can. The difference is that casting silently converts to zero if the `double` is less than `Decimal.MinValue` whereas the constructor throws. – Matthew Nov 23 '11 at 20:50
  • @MatthewPK: Yes, I found the same thing in my research. I've revised my answer accordingly. – James Johnson Nov 23 '11 at 20:53
  • I spoke too soon... apparently the same exceptions are thrown regardless of the method used... – Matthew Nov 23 '11 at 20:59
1

Could try it like this:

double v = 2.33;
decimal b;

if (decimal.TryParse(v.ToString(), out b))
    //do this
else
    //do that
Darren
  • 329
  • 1
  • 6
  • Normally I might consider the `.TryParse` methods but in this case I know that my `double` can be represented as a `decimal`. But I don't think parsing the string value of a double is an effective way of making this conversion.... – Matthew Nov 23 '11 at 22:11
  • 2
    I see your point. My thing is to avoid exceptions where possible and not let exceptions determine code flow. I have found that cast or Contructors or Converters have this tendancy to throw exceptions when things are not right, so I try to avoid them by using "Try" Methods. In this case using a TryParse means I don't need exception handling in case something goes wrong, see: http://msdn.microsoft.com/en-us/library/9zbda557.aspx – Darren Nov 23 '11 at 23:16