6

I'm working with some legacy code right now which usually used try + catch in combination with Convert.ToDecimal(someString) (for instance) to try and convert strings to decimals. For some reasons I have to use the setting that - when debugging - I stop at every thrown exception (not only user-unhandled ones) and so this got annoying and I changed it to use TryParse methods whenever possible.

Now I'm in a situation where there's an object value and a target Type, and all I want to know is if I can convert the value into the target type. Right now this is done as follows:

try
{
  Convert.ChangeType(val, targetType);
}
catch
{
  // Do something else
}

The actual result is not important and is not used further.

While this code is working right now, as I said, it gets a bit annoying and so I wonder: Is there another way of doing the above without having to catch an exception?

I thought of something like IsAssignableFrom on a Type, but this doesn't seem to be applicable in my case (I don't want to assign, I want to know if explicitly converting is possible).

InvisiblePanda
  • 1,589
  • 2
  • 16
  • 39
  • Like to know in which context the code you use is actually being used because the use of Convert.ChangeType [smells](https://en.wikipedia.org/wiki/Code_smell) bad – Dbuggy Nov 11 '15 at 07:54
  • @Dbuggy The code is littered with code smells unfortunately, so I bet you're right. It's in a `ComboBox`-derived (Forms) type named `BindingComboBox` that gets a `DataSource` property (the whole thing is unnecessary IMHO, but I don't have the time to totally change all its uses right now). Then the above code is used to check if the `SelectedValue` is "valid" w.r.t. the `DataType` property of the underlying data source. Since these custom ComboBoxes appear everywhere, I get a LOT of thrown exceptions all the time. – InvisiblePanda Nov 11 '15 at 08:00
  • 1
    Perhaps you created a duplicate to [http://stackoverflow.com/questions/2961656/generic-tryparse](http://stackoverflow.com/questions/2961656/generic-tryparse) – Dbuggy Nov 11 '15 at 08:16
  • @Dbuggy I didn't find that post, but it doesn't seem to be an exact duplicate as it deals with `string` values per se, and I don't know what type might be in my `SelectedValue` property. But nevertheless it gave me some good ideas and I'm looking into the `TypeDescriptor.GetConverter` method right now, as it seems to have `CanConvertFrom` and `CanConvertTo` methods that look like I could use them! Thanks! – InvisiblePanda Nov 11 '15 at 08:42
  • I came by that link as i was thinking that it might be possible to use reflection to invoke the TryParse method (when it exists) of the `targetType` given dynamically. – Dbuggy Nov 11 '15 at 08:53

4 Answers4

3

If you mean casting, than you can use is keyword like:

object someObject = GetSomeObject();
if (someObject is string)
{
    ..
}

But note, that casting and Convert.ChangeType are not the same. For example, you can not cast a string to an int:

string numberString = "15";
int number = (int)numberString;

but you can use ChangeType for it:

string numberString = "15";
int number = (int)Convert.ChangeType(numberString, typeof(int));

EDIT:

If you need to test a variable for being convertible to specific type, then why not just wrap try-catch with Convert.ChangeType into a test method:

public bool IsConvertibleTo<T>(object value)
{
    try 
    {
        T convertedValue = (T)Convert.ChangeType(value, typeof(T));
        return true;
    }
    catch (InvalidCastException)
    {
        return false;
    }
    catch (FormatException)
    {
        return false;
    }
    catch (OverflowException)
    {
        return false;
    }
}
  • Hey, sorry I wasn't more clear! You're right and I should reword my question slightly. What I mean is actually "explicitly converting" (there might be different numerical types involved, thus I can't use `is` at all), and this possibly changes the outcome of the question quite a bit. – InvisiblePanda Nov 11 '15 at 08:05
  • I’m not quite sure about what you mean saying it’s impossible to use `is` since different numerical types are involved. Provided you have `object value = 2`, expression `value is int` will return `true`. At the same time expression, say, `value is decimal`, will return `false`, but you anyway can not cast `value` to `decimal` without previously casting it to `int`: `(decimal)value` will fail, while `(decimal)(int)value` will succeed. – Dzmitry Sauchanka Nov 11 '15 at 08:45
  • I can't use `is` because at that time I only know the target type as a `Type`. But you're right, it's very probable that I can't get around a `catch` block, even if that's what I want to avoid. I'll play around some more with the `TypeConverter` class and its methods, but if that doesn't work, I'll accept your answer :) – InvisiblePanda Nov 11 '15 at 10:30
  • I did play around with the `TypeConverter` class, but it doesn't handle cases other than `string` well for built-in types. So what you proposed (and what's in my post above) is the way to go. To not get annoyed, I will use `DebuggerStepThrough` as @verarind proposed. It's just a little sad that I can't make it an extension to the static `Convert` class. – InvisiblePanda Nov 12 '15 at 09:38
2

I'll give you a solution to "hide" exceptions. Sometimes it's neccessary to catch an exception and as you said it's annoying because the debugger will stop on every exception. I know that, but there is a way of doing that:

[DebuggerStepThrough]
public bool CanChangeType(this object instance, Type targetType)
{
  try
  {
    Convert.ChangeType(val, targetType);
    return true;
  }
  catch
  {
    return false;
  }
}

The trick is the DebuggerStepThrough-attribute.

But keep in mind that you'll never be able to debug into such a method. There is no bugfixing without removing the attribute. Knowing that a method should be short - very short and should obviously be free of all errors.

I'm having the same problems with Udp-classes that throw an exception on close. Extracting this short code to a separate method that contains no error works fine.

Sebastian Schumann
  • 3,204
  • 19
  • 37
0

If you want to check the type of val, you should use keyword is like this,

if (val is targetType) {
    ...
}

If you want to convert val to type targetType, you should use keyword as like this,

targetType result = val as targetType;

if (result != null) {
    ...
}

Both of them won't throw an exception out!

Link: https://msdn.microsoft.com/zh-cn/library/cscsdfbt.aspx

Itachi
  • 5,777
  • 2
  • 37
  • 69
  • Unfortunately, `Convert.ChangeType` does more than the `as` parameter, which means if `as`fails, `ChangeType` could succeed. – Oliver Nov 11 '15 at 08:19
  • @Oliver I think that's crazy if it isn't boxing or unboxing operation in failed branch. – Itachi Nov 11 '15 at 08:23
  • Here is an example which would fail with `as`, but succeeds with `Convert.ChangeType`: `Convert.ChangeType("123", typeof(int));`, cause it does not simply cast the given object, instead (hence the name) it converts it (if possible). – Oliver Nov 11 '15 at 11:12
-1

Your initial guess is right.

    public static bool CanChangeType(Type type)
    {
        return typeof (IConvertible).IsAssignableFrom(type);
    }

is the right way to check by type whether Convert.ChangeType will work or not (as the exception message usually indicates). Not sure why you're opposed to this method because of the "Assign" in it's name. It's just performing some checking on the type. Other than that it doesn't actually do any assigning.

Dbl
  • 5,634
  • 3
  • 41
  • 66
  • Hello Andreas, the question is not about whether the `ChangeType` method is applicable, but rather about its success in converting the actual value. See the accepted answer and @Verarind's answer :) – InvisiblePanda Nov 12 '15 at 09:40
  • @InvisiblePanda ah ok then. "The actual result is not important and is not used further. While this code is working right now, as I said, it gets a bit annoying and so I wonder: Is there another way of doing the above without having to catch an exception?" seemed to desire another answer than that because my method can be used to tell wether or not converting is possible too – Dbl Nov 14 '15 at 22:17