Не може да се определи, защото няма имплицитно преобразуване с ternery if return

Имам следното действие ASP.NET Web Api 2 с троичен if return:

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

    // ...

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

получавам a

Типът на условния израз не може да бъде определен, тъй като няма имплицитно преобразуване между „System.Web.Http.Results.OkResult“ и „System.Web.Http.Results.NotFoundResult“

когато и двамата прилагат IHttpActionResult.

Ако обаче премахна троичния if, компилаторът е доволен:

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

Защо е това?


person Sam Leach    schedule 07.01.2015    source източник


Отговори (2)


Трябва изрично да прехвърлите резултата към 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. Ето защо за нас е достатъчно да "подскажем" компилатора само веднъж от нашия тип cast.

@dcastro е посочил точната част от езиковата спецификация, която определя контрола на типа, вижте това за дефиницията в учебника.

person Yuval Itzchakov    schedule 07.01.2015
comment
@GrantWinney Да, така е - person dcastro; 07.01.2015
comment
@GrantWinney най-важното е, че може да има други типове, които и двата типа изпълняват, така че трябва да кажете на компилатора кой тип искате да прехвърлите. например, ако и двамата прилагат кастинг на интерфейс IFoo, това също би било валидно. това не е случаят в оператора if, защото компилаторът знае типа на връщането. - person Selman Genç; 07.01.2015
comment
@GrantWinney Имах предвид, че ако не прехвърляте, няма начин троичният да определи връщания тип на израза. приемем, че и двете изпълняват IBar и IFoo, типът на връщането трябва да бъде IBar или IFoo? компилаторът не може да знае това и не може да избере произволен тип. - person Selman Genç; 07.01.2015
comment
@GrantWinney По-лесно е да разберете какво се случва, ако напълно забравите за връщания тип на метода. Изразът се оценява независимо. Въпросът е, ако a и b имплементират както IFoo, така и IBar, какъв тип ще бъде x в този израз: var x = bool? a : b - person dcastro; 07.01.2015
comment
Това няма смисъл, тъй като кастингът и на двете към IActionResult работи.... което resharper твърди (с право) е излишно кастиране. - person Shawn; 09.08.2017

В троичен израз A? B : C трябва да има референтно преобразуване (напр. от базов тип в производен тип или обратно) от B към C или C към B.

Очаквахте компилаторът да намери най-извлечения общ предшественик на двата типа (който е IHttpActionResult) - компилаторът не прави това.

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

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

Вторият и третият операнд, x и y, на оператора ?: контролират типа на условния израз.

  • If x has type X and y has type Y then
    • If an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression
    • Ако съществува имплицитно преобразуване (§6.1) от Y към X, но не и от X към Y, тогава X е типът на условния израз.
    • В противен случай не може да се определи тип израз и възниква грешка по време на компилиране
person dcastro    schedule 07.01.2015