21

I have this simple piece of code:

public static int GetInt(int number)
{
    int[] ints = new int[]{ 3, 7, 9, int.MaxValue };
    foreach (int i in ints)
        if (number <= i)
            return i;

    return int.MaxValue; //this should be unreachable code since the last int is int.MaxValue and number <= int.MaxValue is allways true so the above code will allways return
}

The problem is that the compiler says that not every execution path returns a value. So I have to write code that will be never reached. My question is, what should I do in a situation like this? Should I return some default value or should I throw an exception. Also, if I want to throw an exception, what exception is suitable for throwing? I didn't find anything like UnreachableCodeException.

Cyral
  • 13,999
  • 6
  • 50
  • 90
Bosak
  • 2,103
  • 4
  • 24
  • 43
  • 1
    You can declare `i` out of the `foreach` and halt on condition `number <= i` with a `break`, and then you have only one `return` – MilkyWayJoe Jun 06 '13 at 15:48

8 Answers8

28

I'd be tempted to use InvalidOperationException - or some other exception which you wouldn't explicitly catch. Give it a message which indicates that you really didn't expect to get here. This is a "world is seriously broken" failure. InvalidOperationException doesn't quite capture this, but I can't think of a better one offhand. You could always create your own exception to use throughout your codebase, of course.

Don't just return a value, as otherwise you'll never find out if your world is upside-down.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • So there is no built-in .NET exception for unreachable code? I'm not so sure about using `InvalidOperationException`. Isn't there any logic failure exception or something more close to the problem? – Bosak Jun 06 '13 at 15:59
  • On a secound tought `InvalidOperationException` is good when I saw what `IEnumerable.First()` throws `InvalidOperationException` when no item is found. – Bosak Jun 06 '13 at 16:03
  • 1
    @Bosak: Well, `InvalidOperationException` makes more sense for `First` than it does for your case. That really is calling a method when it's not in a valid state - in your case, it's something you really, really don't think should happen. (Assuming you already know that the array is non-empty and contains `int.MaxValue`.) – Jon Skeet Jun 06 '13 at 16:17
  • `NotImplementedException` looks a good candidate since it's never meant to be caught or expected in production code. – ivan_pozdeev Feb 03 '15 at 17:00
  • 1
    @ivan_pozdeev: But to me that usually suggests that there's a code path which *could* reach it, but we've not implemented that functionality yet. – Jon Skeet Feb 03 '15 at 17:01
  • @JonSkeet see the edit that puts stress on "production code". Besides, there is logic in this: if a program got into such a situation, then something had happened that there are no (implemented) means to handle. (maybe, say, another member had been added to an enum) – ivan_pozdeev Feb 03 '15 at 17:08
  • @ivan_pozdeev: I agree that it shouldn't be in production code - which means I'd be surprised to see it in production-ready source code. It would make me think that it had slipped past code review. I still think InvalidOperationException with a suitable message is clearer, but it really is a matter of opinion. – Jon Skeet Feb 03 '15 at 17:11
12

Use the following to show a logic failure message after your foreach:

System.Diagnostics.Debug.Fail("Unreachable code reached");

This will alert you during debugging.

In addition, also throw an exception for during production:

throw new InvalidOperationException();

Do not just return a value, especially one that is potentially valid: you'll never catch the logic error.

Matt Houser
  • 33,983
  • 6
  • 70
  • 88
  • 6
    Using both Debug.Fail and an exception is a good idea; this calls out that the exception is not intended to actually be an executable code path. However I'd choose a better exception than `new Exception`. Jon suggests `InvalidOperationException` which seems reasonable. – Eric Lippert Jun 06 '13 at 15:55
8

.NET 7 introduced the new UnreachableException class for this purpose, as I just learned by watching the YouTube video The new .NET Exception that should NEVER be thrown by Nick Chapsas.

throw new UnreachableException();
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
5

I think every case is different, but yes, ultimately you have to return something or throw an exception. The way to handle this in your code example is just to remove int.MaxValue from your array:

public static int GetInt(int number)
{
    int[] ints = new int[]{ 3, 7, 9 };
    foreach (int i in ints)
        if (number <= i)
            return i;
    return int.MaxValue;
}
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
5

Rather than returning from your loop, declare a return value variable, set it, and then return once at the end of the code.

public static int GetInt(int number)
{
    var rtnVal = int.MaxValue;
    int[] ints = new int[]{ 3, 7, 9, int.MaxValue };
    foreach (int i in ints) {
        if (number <= i) {
            rtnVal = i;
            break;
        }
    }
    return rtnVal;
}
Bill Gregg
  • 7,067
  • 2
  • 22
  • 39
3

Here's a LINQ option that automatically throws an exception when no match is found

public static int GetInt(int number)
{
    int[] ints = new int[]{ 3, 7, 9, int.MaxValue };
    return ints.First(i => number <= i);
}
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
0

The compiler cannot tell that your foreach loop will always return a value.

A theoretical compiler could do so since in principal the information is available, but the C# compiler cannot.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
0

Why not just return the first value that is greater than number instead

    public static int GetInt(int number)
    {
        var ints = new[] { 3, 7, 9};
        return (ints.Any(i => i > number))? 
            ints.First(i => i > number): int.MaxValue;
    }
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216