2

I want to cast a string to a decimal?. With reference to a previous question here

one of the answers gave a object extension to convert objects like so

public static class ObjectExtensions
{
    public static Nullable<T> ToNullable<T>(this object input)
        where T : struct
    {
        if (input == null)
            return null;
        if (input is Nullable<T> || input is T)
            return (Nullable<T>)input;
        throw new InvalidCastException();
    }
}

usage :

object value = 123.45m;
decimal? dec = value.ToNullable<decimal>();

The above does not work with string however, is it possible to define a companion to the above method to specifically handle strings?

specifically like what I would like to be able to do is :-

object v1 = 123.45m;
decimal? d1 = v1.ToNullable<decimal>();

object v2 = "123.45";
decimal? d2 = v2.ToNullable<decimal>();
Community
  • 1
  • 1
mfc
  • 3,018
  • 5
  • 31
  • 43
  • 3
    What do you mean it doesn't work with string ? , string is a reference type, it is not a struct. – Habib Oct 03 '14 at 13:37
  • I think maybe they want to pass a string as an input and have it output a `decimal`? So: `string value = "123.45"; decimal? dec = value.ToNullable();`? EDIT: Of course, if this is the case, at this point you can't simply cast. You'd have to invoke `Decimal.Parse` or some equivalent to do the conversion. – Chris Sinclair Oct 03 '14 at 13:41
  • Better to use Decimal.Parse or Decimal.TryParse to parse the string. That way anyone reading your code will know exactly what culture and number styles you want to accept, without going to look at a custom extension method. – Joe Oct 03 '14 at 13:54

4 Answers4

3

A simple extension method converts string to decimal. For not null strings of course

public static class StringExtensions
{
   public static decimal? ToNullableDecimal(this string s)
   {
      decimal value;
      if (!Decimal.TryParse(s, out value)
         return null;
      return value;
   }
}
Sarrus
  • 586
  • 7
  • 21
2

You could do something like this:

string nds = null;
decimal? d = (nds != null) ? Convert.ToDecimal(nds) : default(decimal?);
dannydk
  • 204
  • 2
  • 4
  • ok, but how do i define the generic extension method part? I thought it was possible to define a general generic method and then a specifically typed generic methods to handle specific types? – mfc Oct 03 '14 at 13:45
  • The method you provided handles them "generally" by simply performing a type cast or unboxing. It's really not converting between types. It's simply unboxing a boxed decimal already. What you're asking for now is to convert/parse a string into _any arbitrary value-type_, or at minimum, the various numeric value types. You could create a method that checks for various use case scenarios, but otherwise default to `Convert.ChangeType(input, typeof(T))` and hope you've supplied two compatible types. – Chris Sinclair Oct 03 '14 at 13:51
2

Given your extension function, why not something like :

public static class ObjectExtensions
    {
        public static Nullable<T> ToNullable<T>(this object input)
            where T : struct
        {
            if (input == null)
                return null;
            if (input is Nullable<T> || input is T)
                return (Nullable<T>)input;
            else if (input is string)
                return (T)Convert.ChangeType(input, typeof(T));

            throw new InvalidCastException();
        }
    }

It will work for numeric types (supported by ChangeType), and even Dates and so.

Of course, "input" must be convertible to desired type (beware of culture-specific constraints).

To improve this, you could pass to "ChangeType" (at third parameter) the Culture you want to work with, for example return ((T)Convert.ChangeType(input, typeof(T), new CultureInfo("en-US")));

You can also add stuff in this method to handle exceptions, etc

AFract
  • 8,868
  • 6
  • 48
  • 70
  • perfect, thanks a lot. was confused by the T: struct. i thought i couldn't pass a string in. – mfc Oct 03 '14 at 13:57
  • @mfc I've edited my post with a few indications about Culture. About your remark, please note "T:struct" applies to output, so it has nothing to do with input which is "object". – AFract Oct 03 '14 at 14:00
0

Here is what is work for me

1- Create following method inside a class (ex ValidationHelper)

     public static decimal? Todecimal(string s,decimal defValue=0)
    {
        if (s.Trim()!="")
        {
            return Convert.ToDecimal(s);
        }
        else
        {
            return defValue;
        }
    }

and then you can use it anywhere in your app like this

prod.Qty = ValidationHelper.Todecimal(txtQty.Text,1);//ex: assuming the default value for Qty is 1. 

Hope this will help someone. Thanks

user2662006
  • 2,246
  • 22
  • 16