Dela via


Target-Typed Villkorsuttryck

Not

Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.

Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader dokumenteras i de relevanta LDM-anteckningarna (Language Design Meeting) .

Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.

Champion-problem: https://github.com/dotnet/csharplang/issues/2460

Konvertering av villkorsuttryck

För ett villkorsuttryck c ? e1 : e2, när

  1. det inte finns någon vanlig typ för e1 och e2, eller
  2. för vilka en gemensam typ finns men ett av uttrycken e1 eller e2 inte har någon implicit konvertering till den typen

vi definierar en ny implicit konvertering av villkorsstyrda uttryck som tillåter en implicit konvertering från villkorsuttrycket till alla typer T där det finns en konvertering från uttryck från e1 till T och även från e2 till T. Det är ett fel om ett villkorsuttryck varken har någon gemensam typ mellan e1 och e2 och inte heller är föremål för en konvertering av villkorsuttryck.

Bättre konvertering från uttryck

Vi ändrar

Bättre konvertering från uttryck

Med en implicit konvertering C1 som konverteras från ett uttryck E till en typ T1och en implicit konvertering C2 som konverteras från ett uttryck E till en typ T2är C1 en bättre konvertering än C2 om E inte exakt matchar T2 och minst något av följande gäller:

till

Bättre konvertering från uttryck

Med en implicit konvertering C1 som konverteras från ett uttryck E till en typ T1och en implicit konvertering C2 som konverteras från ett uttryck E till en typ T2är C1 en bättre konvertering än C2 om E inte exakt matchar T2 och minst något av följande gäller:

  • E matchar exakt T1 (§12.6.4.5)
  • C1 är inte en konvertering av villkorsstyrda uttryck och C2 är en konvertering av villkorsuttryck.
  • T1 är ett bättre konverteringsmål än T2 (§12.6.4.7) och antingen C1 eller C2 är både konverteringar av villkorsuttryck eller ingen är en konvertering av villkorsuttryck.

Cast-uttryck

Den aktuella C#-språkspecifikationen säger

En cast_expression i formen (T)E, där T är en typ och E är en unary_expression, utför en explicit konvertering (§10.3) av värdet för E till typen T.

Vid närvaro av villkorsstyrda uttryck kan det finnas fler än en möjlig konvertering från E till T. Med tillägg av konvertering av villkorsuttryckföredrar vi alla andra konverteringar till en konvertering av villkorsuttryckoch använder konverteringen villkorsuttryck endast som en sista utväg.

Designanteckningar

Anledningen till ändringen i Bättre konvertering av uttryck är att hantera ett fall som detta:

M(b ? 1 : 2);

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

Den här metoden har två små nackdelar. För det första är det inte riktigt samma som switchuttrycket:

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

Detta är fortfarande en icke-bakåtkompatibel ändring, men omfånget är mindre troligt att det påverkar verkliga program:

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

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

Detta blir tvetydigt eftersom konverteringen till long är bättre för det första argumentet (eftersom den inte använder konvertering av villkorsuttryck), men konverteringen till short är bättre för det andra argumentet (eftersom short är ett bättre konverteringsmål än long). Den här ändringen som bryter mot bakåtkompatibilitet verkar mindre allvarlig eftersom den inte ändrar beteendet hos ett befintligt program utan varning.

Anledningen till anmärkningarna på cast-uttrycket är att hantera ett fall som detta:

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

Det här programmet använder för närvarande den explicita konverteringen från int till short, och vi vill bevara den aktuella språk innebörden av det här programmet. Ändringen skulle inte kunna observeras vid körning, men med följande program skulle ändringen vara observerbar:

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

där c är av typen C, d är av typen Doch det finns en implicit användardefinierad konvertering från C till Doch en implicit användardefinierad konvertering från D till Aoch en implicit användardefinierad konvertering från C till A. Om den här koden kompileras före C# 9.0 konverterar vi från b till c sedan till Dnär A är sant. Om vi använder konverteringen av det villkorsstyrda uttrycket , konverterar vi direkt från b till c när A är sant, vilket resulterar i att en annan sekvens av användarkod körs. Därför behandlar vi konvertering av villkorsuttryck som en sista utväg i en cast för att bevara befintligt beteende.