Search code examples
c#castinginteger

Check if variable of any type can be cast into an int in C#?


(int)value is causing exceptions because sometimes value is not an int. I want this code to handle values of multiple types, and cast to an int if possible so I can check what that int's value is (for example, casting an Enum to an int).

checking for value as int == null doesn't work because int isn't a nullable type.

checking for value is int doesn't appear to do the same thing; an Enum will return false even though it can be converted.

Int32.TryParse() doesn't work because the source value must be a string.

I even tried typeof(int).IsAssignableFrom(value.GetType()) but that fails, presumably because it needs an explicit rather than implicit cast.

my best guess is to simply do a try-catch for the cast, but that's also awkward since I want to handle the lack of an exception (if value can be cast into int, do thing), not the exception. since the function just exits after this check I can just put a return in the catch and assume anything after the return can be cast to an int, but yeah that seems pretty hacky and not a great general-purpose solution. Any better ideas?

Edit: this question got closed for being a dupe of Better way to cast object to int

but 'a better way to cast' to int is not the same as checking if you can pre-cast.

the as int? doesn't work because my test Enum still evaluates to null.

Convert.ToInt32() doesn't work because it return 0 if the cast failed and the value if it succeeded, making it impossible to tell if it succeeded a cast to 0 or it failed.

OP's solution won't work, it'll evaluate the Enum to its name, not its int index.

Thankfully by thinking about it a tad more myself, I realized there's a pretty obvious solution.

bool canCastToInt(object o)
{
    try
    {
        o = (int)o;
    }
    catch (Exception)
    {
        return false;
    }
    return true;
}

Tada.


Solution

  • I would write it using a "Try" syntax (like int.TryParse()) like so:

    public static bool TryCastToInt(object obj, out int result)
    {
        try
        {
            result = (int) obj;
            return true;
        }
    
        catch
        {
            result = 0;
            return false;
        }
    }
    

    However, note that this cast will fail unless the object is an enum with underlying type int or an actual int. For example, it will fail for short and double.

    If you want it to work for any type that can be explicitly cast to int you can implement it using Convert.ChangeType() like so:

    public static bool TryCastToInt(object obj, out int result)
    {
        try
        {
            result = (int) Convert.ChangeType(obj, typeof(int));
            return true;
        }
    
        catch
        {
            result = 0;
            return false;
        }
    }
    

    To see the difference, try the following console app:

    namespace Console1;
    
    public static class Program
    {
        enum ShortEnum: short { Item }
        enum IntEnum { Item }
    
        public static void Main()
        {
            test(1.234, "double");
            test("x", "string");
            test((short)1, "short");
            test(ShortEnum.Item, "short enum");
            test(IntEnum.Item, "int enum");
            test(1, "int");
        }
    
        static void test(object obj, string name)
        {
            if (TryCastToInt(obj, out int value))
                Console.WriteLine($"{name} = {value}");
            else
                Console.WriteLine($"Could not cast {name} to int.");
        }
    
        public static bool TryCastToInt(object obj, out int result)
        {
            try
            {
                // result = (int)obj;
                result = (int) Convert.ChangeType(obj, typeof(int));
                return true;
            }
    
            catch
            {
                result = 0;
                return false;
            }
        }
    }
    

    Run this to see the results, and then comment out the ChangeType() line and uncomment the (int) line and run it again.