6
\$\begingroup\$

In a case like this:

object A1 = null;
Decimal? B = Convert.ToDecimal(A1);
object A2 = null;
int? C = Convert.ToInt32(A2);

Note that in case where A1 or A2 have values, they appear to be of type double.

B and C will be 0 instead of null. A1 actually comes from Excel via the interop and (Decimal?)A1 throws an error: Specified cast is not valid. yet Convert.ToDecimal(A1) works. The problem is that if A1 is null, I want B to also be null

So at the moment I'm solving it like this:

Func<object, Decimal?> convertOrNullDecimal = x => x == null ? (Decimal?)null : Convert.ToDecimal(x);
Func<object, int?> convertOrNullInt32 = x => x == null ? (int?)null : Convert.ToInt32(x);

B = convertOrNullDecimal(A1);
C = convertOrNullDecimal(A2);

Is this a reasonable way to go? Or can I refactor that into a single function? It's possible I'll have to add other numeric data types later on...

I tried it like this:

public static Decimal? convertOrNull(object x)
{
    return x == null ? (Decimal?)null : Convert.ToDecimal(x);
}
public static int? convertOrNull(object x)
{
    return x == null ? (int?)null : Convert.ToInt32(x);
}

but then the calls become ambiguous. I guess you can't overload based on output variable type...

Also note that if I try B = A1 as Decimal?, then if A1 had a numerical value, B is still null because it looks like Excel passed numeric cells as doubles and empty cells as null

\$\endgroup\$
  • 3
    \$\begingroup\$ okay... what's your question? I don't understand where you're going... This reads more like a "I have problem x and I want it solved." and not like "I have solved problem x, is this solution good?" \$\endgroup\$ – Vogel612 Oct 28 '14 at 16:57
  • 1
    \$\begingroup\$ @Vogel612 it is solved - it works. My question is is there a better way to solve it than making a function (like mine above) for each input type? \$\endgroup\$ – Dan Oct 28 '14 at 16:58
13
\$\begingroup\$

If you know that the object is always either double or null, then that's exactly what the double? type can represent and you can convert to that using a cast:

object obj = ...;
double? doubleValue = (double?)obj;

And once you have double?, you can cast it to decimal? and it will work both for the case when the value is null and when isn't:

decimal? decimalValue = (decimal?)doubleValue;

Or, on a single line:

decimal? decimalValue = (decimal?)(double?)obj;

Apart from being clear, this approach is also likely going to be pretty efficient.

| improve this answer | |
\$\endgroup\$
8
\$\begingroup\$

Use generics that's all:

    public static T? ConvertTo<T>(object x) where T : struct
    {
        return x == null ? null : (T?)Convert.ChangeType(x, typeof(T));
    }
| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

I am not sure why you are worried about doubles coming through instead of Decimals but you could just assign with a ternary like this

var B = A1 == null ? null : A1;

This way B will be the same type as A1

Most of the time a Method or Function that takes a Decimal value should also take a Double value, Doubles are smaller than Decimals

Single, Double, Decimal are kind of like Integer types

  • Single = 4 bytes (short = 2 bytes)
  • Double = 8 Bytes (int = 4 bytes)
  • Decimal = 12 bytes (long = 8 bytes)

(Decimal vs. Double)


Note: Assuming that decimal values are necessary

You could just do the conversion after you assign to the variable (after checking for null).

You might be able to assign straight across actually

decimal B = A1 == null ? null : A1;

but you need a nullable decimal (decimal?) Another Assumption

Instead of assigning null to the Decimal you have to assign it's default value using default(decimal?) which I assume comes out as null.

decimal? B = A1 == null ? default(decimal?) : Convert.ToDecimal(A1);

Google and MSDN are awesome resources to figure stuff like this out.

(as well as StackOverflow answers)


playing around with this if you don't want a nullable Decimal you can also write it like this

decimal C = A1 == null ? default(decimal) : Convert.ToDecimal(A1);
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Yes, default(decimal?) is the same as null. And instead of default(decimal), you can write just 0m. \$\endgroup\$ – svick Oct 29 '14 at 12:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.