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

У меня есть следующее действие 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, компилятор счастлив:

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

Почему это?

3 ответа

Решение

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

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

Редактировать:

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

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

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

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 ссылается на точную часть спецификации языка, которая определяет контроль над типом, см. это для определения учебника.

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

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

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

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

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

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

Начиная с C# 9.0, пример OP будет успешно компилироваться , потому что тип результата тернарного условного выражения теперь основан на целевом типе . Раньше он основывался на типах операндов; они должны были быть равны или один операнд должен был быть неявно преобразован в другой.

Другие вопросы по тегам