Udostępnij za pośrednictwem


wyrażenie warunkowe Target-Typed

Notatka

Ten artykuł jest specyfikacją funkcji. Specyfikacja służy jako dokument projektowy dla funkcji. Zawiera proponowane zmiany specyfikacji wraz z informacjami wymaganymi podczas projektowania i opracowywania funkcji. Te artykuły są publikowane do momentu sfinalizowania proponowanych zmian specyfikacji i włączenia ich do obecnej specyfikacji ECMA.

Mogą wystąpić pewne rozbieżności między specyfikacją funkcji a ukończoną implementacją. Te różnice są odnotowane w odpowiednich notatkach ze spotkania dotyczącego projektowania języka (LDM) .

Więcej informacji na temat procesu wdrażania specyfikacji funkcji można znaleźć w standardzie języka C# w artykule dotyczącym specyfikacji .

Konwersja wyrażeń warunkowych

W przypadku wyrażenia warunkowego c ? e1 : e2, kiedy

  1. nie ma typowego typu dla e1 i e2, lub
  2. dla którego typ wspólny istnieje, ale jedno z wyrażeń e1 lub e2 nie ma niejawnej konwersji na ten typ

Definiujemy nową niejawną konwersję wyrażenia warunkowego , która pozwala na konwersję z wyrażenia warunkowego na dowolny typ T, dla którego istnieje konwersja z wyrażenia z e1 do T oraz z e2 do T. Jest to błąd, gdy wyrażenie warunkowe nie ma wspólnego typu między e1 a e2 ani nie jest poddane konwersji wyrażenia warunkowego .

Lepsza konwersja z wyrażenia

Zmieniamy

Lepsza konwersja z wyrażenia

Biorąc pod uwagę niejawną konwersję C1, która konwertuje wyrażenie E na typ T1, oraz niejawną konwersję C2, która konwertuje wyrażenie E na typ T2, C1 jest lepszą konwersją niż C2, jeśli E nie dokładnie odpowiada T2 i co najmniej jedna z następujących zaszłości zachodzi:

do

Lepsza konwersja wyrażenia

Biorąc pod uwagę niejawną konwersję C1, która konwertuje z wyrażenia E na typ T1, i niejawną konwersję C2, która konwertuje z wyrażenia E na typ T2, C1 jest lepszą konwersją niż C2, jeśli E nie jest dokładnie zgodna z T2 i co najmniej jedna z następujących zachodzi:

  • E dokładnie pasuje do T1 (§12.6.4.5)
  • C1 nie jest konwersją wyrażenia warunkowego i C2 to konwersja wyrażenia warunkowego.
  • T1 jest lepszym celem konwersji niż T2 (§12.6.4.7) , a C1 i C2 są albo obie konwersjami wyrażeń warunkowych, albo żadna z nich nie jest konwersją wyrażeń warunkowych.

Wyrażenie rzutu

Bieżąca specyfikacja języka C# mówi

cast_expression formularza (T)E, gdzie T jest typem i E jest unary_expression, wykonuje jawną konwersję (§10.3) wartości E do typu T.

W obecności konwersji wyrażenia warunkowego może istnieć więcej niż jedna możliwa konwersja z E na T. Po dodaniu konwersji wyrażenia warunkowego , preferujemy każdą inną konwersję niż konwersję wyrażenia warunkowego i używamy konwersji wyrażenia warunkowego tylko w ostateczności.

Uwagi dotyczące projektu

Przyczyną zmiany na Lepsza konwersja wyrażenia jest obsługa przypadku takiego jak:

M(b ? 1 : 2);

void M(short);
void M(long);

Takie podejście ma dwa małe wady. Po pierwsze nie jest to samo co wyrażenie przełącznika:

M(b ? 1 : 2); // calls M(long)
M(b switch { true => 1, false => 2 }); // calls M(short)

Jest to nadal zmiana przełomowa, ale jej zakres jest mniej prawdopodobny, aby wpłynąć na rzeczywiste programy.

M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature.

M(short, short);
M(long, long);

Staje się to niejednoznaczne, ponieważ konwersja na long jest lepsza dla pierwszego argumentu (ponieważ nie używa konwersji wyrażenia warunkowego), ale konwersja na short jest lepsza dla drugiego argumentu (ponieważ short jest lepszym celem konwersji niż long). Ta zmiana powodująca niezgodność wydaje się mniej poważna, ponieważ nie zmienia ona niepostrzeżenie zachowania istniejącego programu.

Przyczyną notatek w wyrażeniu rzutowania jest obsługa takiego przypadku:

_ = (short)(b ? 1 : 2);

Ten program używa obecnie jawnej konwersji z int do shorti chcemy zachować bieżące znaczenie języka tego programu. Zmiana byłaby nieobserwowalna w czasie wykonywania, ale w przypadku następującego programu zmiana byłaby zauważalna:

_ = (A)(b ? c : d);

gdzie c jest typu C, d jest typu D, i istnieje niejawna konwersja zdefiniowana przez użytkownika z C na D, a niejawna konwersja zdefiniowana przez użytkownika z D na Ai niejawna konwersja zdefiniowana przez użytkownika z C na A. Jeśli ten kod jest kompilowany przed C# 9.0, gdy b ma wartość true, przekonwertujemy z c na D, a następnie na A. Jeśli używamy konwersji wyrażenia warunkowego , to gdy b jest prawdziwe, dokonujemy bezpośredniej konwersji z c na A, co powoduje wykonanie innej sekwencji kodu użytkownika. W związku z tym traktujemy konwersję wyrażenia warunkowego jako ostateczne rozwiązanie w przypadku rzutowania, aby zachować istniejące zachowanie.