1

Suppose the following method:

public static bool IsNumber<T>(string number) where T : struct ...
try
{
   var numberConverted = (T) Convert.ChangeType(text, typeof(T));
   return true;
}
catch (...

The idea is to call it like this:

var number = "$1,123.00";
var numberOk = IsNumber<decimal>(number);

The issue is that no matter what, I can't find a way to Convert.ChangeType to accept numbers with the currency symbol (already tried passing in a IFormatProvider with no success).

Is there a way to specify a NumberStyles when using Convert.ChangeType, or something different that would allow me to use the method IsNumber<T> even if the string to check has a currency symbol?

Edit Jul-3-2016 9 PM UTC:

The idea is that this method verifies everything that the type T requires. If I put a simple decimal.Parse and include a NumberStyles.Currency paramater, it will not validate that number is an integer and should not have decimals, or that number is a float and the minimum and maximum value are different than the ones for decimal. In other words, in a global and generic solution, I have no access to a Parse-like method or something that accepts a NumberStyles parameter.

This edit is to explain why I think that this is no duplicate of the question Problem parsing currency text to decimal type

Community
  • 1
  • 1
mishamosher
  • 1,003
  • 1
  • 13
  • 28
  • Possible duplicate of [Problem parsing currency text to decimal type](http://stackoverflow.com/questions/4953037/problem-parsing-currency-text-to-decimal-type) – user247702 Jul 03 '16 at 20:56
  • @Stijn I do not see a duplicate, that question specifically states **Problem parsing currency text to _decimal_ type**, I'm asking for a global solution (not specifically decimal types only), case in which I have no `Parse` method to give a `NumberStyles` – mishamosher Jul 03 '16 at 21:00
  • You don't really believe that `Convert.ChangeType` works generically for every type, right? All it supports is a few system value types and string. – Ivan Stoev Jul 03 '16 at 21:38
  • @IvanStoev I can define a new type called `BigDecimal` and correctly implement the interface `IConvertible`. Then `Convert.ChangeType` will work for my new and custom type `BigDecimal`. – mishamosher Jul 03 '16 at 21:48
  • @mishamosher you an also use that method for other numeric types. There's no reason to try and make a generic method in this case imho. In addition to that, if you're dealing with currency, you **need** the precision of a decimal. – user247702 Jul 03 '16 at 21:55
  • @IvanStoev Oh, and I can also implemet an implicit or explicit operator in my `BigDecimal` definition that allows casting from `string` to `BigDecimal`. `Convert.ChangeType` will work in that case too. – mishamosher Jul 03 '16 at 21:57
  • @Stijn True, but it would require some ugly reflection to check if the type `T` has a method called `Parse` with the right parameters and use it. Would like something that won't require such a thing (: – mishamosher Jul 03 '16 at 22:01
  • @Stijn (Responding to your edit) I'm dealing with the currency symbol, not with a string that necessarily has a monetary number on it. – mishamosher Jul 03 '16 at 22:07
  • 1
    No, it will not. See [here](http://referencesource.microsoft.com/#mscorlib/system/convert.cs,3bcca7a9bda4114e) and [here](http://referencesource.microsoft.com/#mscorlib/system/convert.cs,d804414ae6829e79). Remember the active class in this case is the `string`. You really have to make your own methods. – Ivan Stoev Jul 03 '16 at 22:09
  • 1
    @IvanStoev I love how the Microsoft Refence Source leaves no place to doubts (: - Thanks for illuminating me. Anyway, even with only built-in types support for `Convert.ChangeType`, it will suffice my needs, case in which all of them (except for string) have a `Parse` method. Will redact an answer with this `Parse` solution, as it solved my problem. – mishamosher Jul 03 '16 at 22:17

1 Answers1

1

In my specific scenario I required this to work only with the built-in .Net types. Every numeric type has a Parse method, and as pointed by Stijn in the comments, Parse has an overload that accepts a NumberStyles parameter. Also, it is important to note that Convert.ChangeType works only with a very limited subset of the built-in .Net types, as pointed by Ivan Stoev in the comments. Thanks for the valuable comments!

And now the working solution, I've just made a little tweak into the IsNumber<T> method using some reflection:

public static bool IsNumber<T>(string number, NumberStyles numberStyle) where T : struct ...
try
{
    var mi = typeof(T).GetMethod("Parse", new Type[] {typeof(string), typeof(NumberStyles)});
    if (mi == null)
        return false;
    var parsed = mi.Invoke(null, new object[] {number, numberStyle});
    return true;
}
catch (...

Method should be called like:

var number = "$1,123.00";
var numberOk = IsNumber<decimal>(number, NumberStyles.Currency);
Community
  • 1
  • 1
mishamosher
  • 1,003
  • 1
  • 13
  • 28