Как я могу избежать невозможного логического состояния в С#?

Рассмотрим эту функцию, которую вы можете рассматривать как таблицу истинности:

public Foo doSomething(bool a, bool b) {

       if ( a &&  b) return doAB();
  else if ( a && !b) return doA();
  else if (!a &&  b) return doB();
  else if (!a && !b) return doNotANotB();

  else throw new Exception("Well done, you defeated boolean logic!");
}

Компилятор настаивает на этом последнем предложении else. Но с точки зрения таблицы правды это невозможно.

Да, это работает, и да, я могу жить с ним. Но мне интересно, есть ли какой-то механизм в С#, чтобы избежать такого рода кода, или если я пропустил что-то очевидное?

UPDATE:
Для бонусных очков и чисто из любопытства существуют ли какие-либо языки, которые занимаются подобным делом по-разному? Может быть, это не язык, а скорее один из умного компилятора (но случаи с краем были бы невообразимо сложными, я полагаю).

Ответ 1

Учитывая таблицу истинности, последнее условие полностью суперфлюо. Его можно отбросить без изменения логики вашей программы, например:

public MyType doSomething(bool a, bool b) {

      if ( a &&  b) return doAB();
else  if ( a && !b) return doA();
else  if (!a &&  b) return doB();
else/*if (!a && !b)*/ return doNotANotB();
}

Теперь у вас есть окончательный catch-all if, и ваш компилятор счастлив. Вам не нужно вообще удалять это условие - мне часто кажется, что это хорошая идея, чтобы сохранить его в комментарии для удобочитаемости.

Ответ 2

if(a) return b ? doAB() : doA();
else return b ? doB() : doNotAnotB();

Или короче:

return a ? (b ? doAB() : doA())
         : (b ? doB() : doNotAnotB());

Ответ 3

Попробуйте f #. Если он может обнаруживать соответствие полного соответствия с его директивой соответствия, то он не требует другого.

http://ganesansenthilvel.blogspot.co.at/2011/12/f-pattern-matching.html?m=1#!

> let testAND x y =
match x, y with
| true, true -> true
| true, false -> false
| false, true -> false
| false, false -> true

> testAND true false;;
val it: bool = true

и для неполной спецификации

> let testAND x y =
match x, y with
| true, true -> true
// Commented | true, false -> false 
| false, true -> false
| false, false -> true
> testAND true false;;

компилятор скажет

Microsoft.Fsharp.Core.MatchFailureExcption: The match cases were incomplete at:....
Stopped due to error

Ответ 4

 public MyType doSomething(bool a, bool b)
        {
            switch(a)
            {
                case true:
                    if (b) return doAB();
                    return doA();
                default:
                    if (b) return doB();
                    return doNotANotB();

            }

        }

Update:

Обратите внимание, что ваш исходный оператор на самом деле:

  public MyType doSomething(bool a, bool b)
        {
            if (a && b) return doAB();
            if (a) return doA();
            if (b) return doB();
            return doNotANotB();
        }

Для удовольствия и сукцинтов (если не читаемость: p):

static MyType doSomething(bool a, bool b)
        {
            return a && b ? doAB() : a ? doA() : b ? doB() : doNotANotB();
        }