"Невозможно определить, потому что нет никакого неявного преобразования" с тернерой, если возвращение

У меня есть следующее действие ASP.NET Web Api 2 с тройным возвратом:

[HttpDelete]
public IHttpActionResult Delete()
{
    bool deleted;

    // ...

    return deleted ? this.Ok() : this.NotFound();
}

Получаю

Тип условного выражения не может быть определен, потому что существует нет неявного преобразования между "System.Web.Http.Results.OkResult" и 'System.Web.Http.Results.NotFoundResult'

когда оба они реализуют IHttpActionResult.

Однако, если я удалю троичный, если, компилятор счастлив:

if (deleted)
{
    return this.Ok();
}
return this.NotFound();

Почему это?

Ответ 1

Вам нужно явно передать результат на IHttpActionResult:

return deleted ? (IHttpActionResult) this.Ok() : this.NotFound();

Edit:

Что касается вопроса о грантах:

Почему второй блок кода Сэма работает без явного IHttpActionResult, просто из любопытства? Это что-то конкретное к условному?: operator?

Позволяет создать простую демонстрацию. Предположим, что следующий код:

public interface IFoo { }

public class B : IFoo { }

public class C : IFoo { }

И затем следующее:

public class A
{
    IFoo F(bool b)
    {
        return b ? (IFoo) new B() : new C();
    }
}

Давайте посмотрим, как компилятор декомпилирует тернарный оператор:

private IFoo F(bool b)
{
    IFoo arg_13_0;
    if (!b)
    {
        IFoo foo = new C();
        arg_13_0 = foo;
    }
    else
    {
        arg_13_0 = new B();
    }
    return arg_13_0;
}

Явное приведение достаточно для компилятора, чтобы сделать вывод о том, что переменная должна иметь тип IFoo и, следовательно, удовлетворять всем нашим if-else. Вот почему нам достаточно "намекнуть" на компилятор только один раз из нашего типа.

@dcastro ссылается на точную часть спецификации языка, которая определяет управление типом, см. это для определения текстовой книги.

Ответ 2

В тройном выражении A? B : C должно быть референсное преобразование (например, от базового типа к производному типу или наоборот) от B до C или C к B.

Вы ожидали, что компилятор найдет наиболее производный общий предок двух типов (который есть IHttpActionResult) - компилятор этого не делает.

Как общее правило, тип результата любого выражения должен содержаться внутри самого выражения. I.e., bool? dog : cat не может вернуть animal, потому что никакая переменная типа animal не является частью выражения.

В разделе "Спецификация языка С#" 7.14 "Условный оператор":

Второй и третий операнды, x и y, оператора?: управляют типом условного выражения.

  • Если x имеет тип X, а y имеет тип Y, тогда
    • Если неявное преобразование (§6.1) существует из X в Y, но не от Y до X, то Y является типом условного выражения
    • Если неявное преобразование (§6.1) существует от Y до X, но не от X до Y, то X является типом условное выражение.
    • В противном случае тип выражения не может быть определен, и возникает ошибка времени компиляции