Is there a try Convert.ToInt32... avoiding exceptions

C#Type Conversion

C# Problem Overview


I'd like to know if there is a "safe" way to convert an object to an int, avoiding exceptions.

I'm looking for something like public static bool TryToInt32(object value, out int result);

I know I could make something like this:

public static bool TryToInt32(object value, out int result)
{
    try
    {
        result = Convert.ToInt32(value);
        return true;
    }
    catch
    {
        result = 0;
        return false;
    }
}

But I'd rather avoid exceptions, because they are slowing down the process.

I think this is more elegant, but it's still "cheap":

public static bool TryToInt32(object value, out int result)
{
    if (value == null)
    {
        result = 0;
        return false;
    }

    return int.TryParse(value.ToString(), out result);
}

Does anyone have better ideas?

UPDATE:

This sounds a little like splitting hairs, but converting an object to string forces the implementer to create a clear ToString() function. For example:

public class Percentage
{
    public int Value { get; set; }

    public override string ToString()
    {
        return string.Format("{0}%", Value);
    }
}

Percentage p = new Percentage();
p.Value = 50;

int v;
if (int.TryParse(p.ToString(), out v))
{
    
}

This goes wrong, I can do two things here, or implement the IConvertable like this:

public static bool ToInt32(object value, out int result)
{
    if (value == null)
    {
        result = 0;
        return false;
    }

    if (value is IConvertible)
    {
        result = ((IConvertible)value).ToInt32(Thread.CurrentThread.CurrentCulture);
        return true;
    }

    return int.TryParse(value.ToString(), out result);
}

But the ToInt32 method of the IConvertible cannot be canceled. So if it's not possible to convert the value, an exception cannot be avoided.

Or two: Is there a way to check if the object contains a implicit operator?

This is very poor:

if (value.GetType().GetMethods().FirstOrDefault(method => method.Name == "op_Implicit" && method.ReturnType == typeof(int)) != null)
{
    result = (int)value;
    return true;
}

C# Solutions


Solution 1 - C#

int variable = 0;
int.TryParse(stringValue, out variable);

If it can't be parsed, the variable will be 0. See http://msdn.microsoft.com/en-us/library/f02979c7.aspx

Solution 2 - C#

Spurring from the comments. The response is no. You can't do what Convert.ToInt32(object) does without having throwed exceptions. You can do something similar (and you already did it). The only thing I would optimize is the case of value already an int.

if (value is int) 
    return (int)value;

You can't do as Convert.ToInt32(object) because Convert.ToInt32(object) doesn't simply test if value is short, int, long, ushort, ... and then cast them. It checks if the value is IConvertible. If yes it uses the IConvertible.ToInt32. Sadly the interface IConvertible is quite poor: it doesn't have non-throwing methods (IConvertible.Try*)

While stupid (but perhaps not too much), someone could make for example a UnixDateTime struct: (UnixTime is the number of seconds from midnight 1970-01-01), where the IConvertible.ToInt32 returns this number of seconds, while the ToString() returns a formatted date. All the int.TryParse(value.ToString(), out parsed) would choke, while the Convert.ToInt32 would work flawlessly.

Solution 3 - C#

No need to re-invent the wheel here. use int.TryParse to achieve your goal. It returns a bool to show that value is parsed or not. and if parsed the result is saved in the output variable.

int result;
object a = 5;
if(int.TryParse(a.ToString(),out result))
{
   Console.WriteLine("value is parsed");  //will print 5
}    

object b = a5;
if(int.TryParse(b.ToString(),out result))
{
    Console.WriteLine("value is parsed");  
}
else
{
    Console.WriteLine("input is not a valid integer");  //will print this   
}

Solution 4 - C#

This version using a type converter would only convert to string as a last resort but also not throw an exception:

public static bool TryToInt32(object value, out int result)
{
	if (value == null)
	{
		result = 0;
		return false;
	}
	var typeConverter =  System.ComponentModel.TypeDescriptor.GetConverter(value);
	if (typeConverter != null && typeConverter.CanConvertTo(typeof(int)))
	{
		var convertTo = typeConverter.ConvertTo(value, typeof(int));
		if (convertTo != null)
		{
			result = (int)convertTo;
			return true;
		}
	}
	return int.TryParse(value.ToString(), out result);
}

Solution 5 - C#

I would use a mixture of what you are already doing;

  • Check if the object is null - return false and the value 0;
  • Attempt to convert directly - if successful, return true and the converted value
  • Attempt to parse value.ToString() - if successfull, return true and the parsed value
  • Any other case - Return false and the value 0, as object is not convertible/parsible

The resulting code:

public static bool TryToInt32(object value, out int result)
{
    result = 0;
    if (value == null)
    {
        return false;
    }

    //Try to convert directly
    try
    {
        result = Convert.ToInt32(value);
        return true;
    }
    catch
    {
        //Could not convert, moving on
    }

    //Try to parse string-representation
    if (Int32.TryParse(value.ToString(), out result))
    {
        return true;
    }

    //If parsing also failed, object cannot be converted or paresed
    return false;
}

Solution 6 - C#

I wrote this mess, looking at it makes me sad.

using System;
using System.Globalization;

internal static class ObjectExt
{
    internal static bool TryConvertToDouble(object value, out double result)
    {
        if (value == null || value is bool)
        {
            result = 0;
            return false;
        }

        if (value is double)
        {
            result = (double)value;
            return true;
        }

        var text = value as string;
        if (text != null)
        {
            return double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out result);
        }

        var convertible = value as IConvertible;
        if (convertible == null)
        {
            result = 0;
            return false;
        }

        try
        {
            result = convertible.ToDouble(CultureInfo.InvariantCulture);
            return true;
        }
        catch (Exception)
        {
            result = 0;
            return false;
        }
    }
}

Edit Notice now I answered for double when the question was int, keeping it any way. Maybe useful for someone.

Solution 7 - C#

Return a nullable int. that way you know whether you parsed 0.

int? value = int.TryParse(stringValue, out int outValue) 
    ? outValue
    : default(int?);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeroen van LangenView Question on Stackoverflow
Solution 1 - C#ranieuweView Answer on Stackoverflow
Solution 2 - C#xanatosView Answer on Stackoverflow
Solution 3 - C#EhsanView Answer on Stackoverflow
Solution 4 - C#Jeremy ThomasView Answer on Stackoverflow
Solution 5 - C#Lars KristensenView Answer on Stackoverflow
Solution 6 - C#Johan LarssonView Answer on Stackoverflow
Solution 7 - C#chris31389View Answer on Stackoverflow