Как я могу избежать невозможного логического состояния в С#?
Рассмотрим эту функцию, которую вы можете рассматривать как таблицу истинности:
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();
}