"Не может быть определено, потому что нет неявного преобразования" с тернери, если возврат
У меня есть следующее действие 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 будет успешно компилироваться , потому что тип результата тернарного условного выражения теперь основан на целевом типе . Раньше он основывался на типах операндов; они должны были быть равны или один операнд должен был быть неявно преобразован в другой.