Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.
Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v příslušných poznámkách ze schůzky jazykového návrhu (LDM).
Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .
Problém šampiona: https://github.com/dotnet/csharplang/issues/8677
Shrnutí
Umožňuje podmíněné přiřazení k výrazu v rámci a?.b nebo a?[b].
using System;
class C
{
public object obj;
}
void M(C? c)
{
c?.obj = new object();
}
using System;
class C
{
public event Action E;
}
void M(C? c)
{
c?.E += () => { Console.WriteLine("handled event E"); };
}
void M(object[]? arr)
{
arr?[42] = new object();
}
Motivation
V různých prosazovaných otázkách lze najít různé příklady použití. Mezi hlavní motivace patří:
- Parita mezi vlastnostmi a
Set()metodami - Připojení obslužných rutin událostí v kódu uživatelského rozhraní
Podrobný návrh
- Pravá strana přiřazení se vyhodnotí pouze v případech, kdy příjemce podmíněného přístupu nemá hodnotu null.
// M() is only executed if 'a' is non-null.
// note: the value of 'a.b' doesn't affect whether things are evaluated here.
a?.b = M();
- Jsou povoleny všechny formy složeného přiřazení.
a?.b -= M(); // ok
a?.b += M(); // ok
// etc.
- Pokud se použije výsledek výrazu, musí být typ výrazu známý jako typ hodnoty nebo odkazový typ. To je konzistentní se stávajícím chováním u podmíněných přístupů.
class C<T>
{
public T? field;
}
void M1<T>(C<T>? c, T t)
{
(c?.field = t).ToString(); // error: 'T' cannot be made nullable.
c?.field = t; // ok
}
- Výrazy podmíněného přístupu stále nejsou lvalues, a například se k nim stále nesmí použít
ref.
M(ref a?.b); // error
- Není povoleno odkazovat na přiřazení k podmíněnému přístupu. Hlavním důvodem je to, že jediným způsobem, jak byste podmíněně přistupovali k proměnné typu ref, je pole typu ref, a struktury typu ref je zakázáno používat v typech hodnot, které mohou nabývat hodnoty null. Pokud se v budoucnu objevil platný scénář podmíněného přiřazení odkazu, mohli bychom přidat podporu.
ref struct RS
{
public ref int b;
}
void M(RS a, ref int x)
{
a?.b = ref x; // error: Operator '?' can't be applied to operand of type 'RS'.
}
- Podmíněné přístupy není například možné přiřazovat prostřednictvím dekonstrukčního přiřazení. Očekáváme, že lidé to budou dělat jen zřídka, takže místo toho nebude to významnou nevýhodou u více samostatných přiřazovacích výrazů.
(a?.b, c?.d) = (x, y); // error
- Operátory přírůstku nebo dekrementace se nepodporují.
a?.b++; // error
--a?.b; // error
- Tato funkce obecně nefunguje, pokud je příjemcem podmíněného přístupu typ hodnoty. Je to proto, že spadá do jednoho z následujících dvou případů:
void Case1(MyStruct a)
=> a?.b = c; // a?.b is not allowed when 'a' is of non-nullable value type
void Case2(MyStruct? a)
=> a?.b = c; // `a.Value` is not a variable, so there's no reasonable meaning to define for the assignment
readonly-setter-calls-on-non-variables.md navrhuje uvolnění, v takovém případě bychom mohli definovat rozumné chování pro a?.b = c, když je aSystem.Nullable<T> a b je vlastnost se setterem pouze pro čtení.
Specifikace
Gramatika podmíněného přiřazení null je definována takto:
null_conditional_assignment
: null_conditional_member_access assignment_operator expression
: null_conditional_element_access assignment_operator expression
Odkazy najdete v článcích §11.7.7 a §11.7.11 .
Když se podmíněné přiřazení null objeví ve výrazovém příkazu, jeho sémantika je následující:
-
P?.A = Bje ekvivalentní hodnotěif (P is not null) P.A = B;, s výjimkou toho, žePse vyhodnotí pouze jednou. -
P?[A] = Bje ekvivalentní hodnotěif (P is not null) P[A] = B, s výjimkou toho, žePse vyhodnotí pouze jednou.
Jinak jsou jeho sémantika následující:
-
P?.A = Bje ekvivalentní(P is null) ? (T?)null : (P.A = B), kdeTje typ výsledkuP.A = B, s výjimkou toho, žePje vyhodnocen pouze jednou. -
P?[A] = Bje ekvivalentní(P is null) ? (T?)null : (P[A] = B), kdeTje typ výsledkuP[A] = B, s výjimkou toho, žePje vyhodnocen pouze jednou.
Implementace
Gramatika v současné době neodpovídá návrhu syntaxe použitému v implementaci. Očekáváme, že po implementaci této funkce zůstane tento případ zachován. U návrhu syntaxe v implementaci se neočekává, že se skutečně změní pouze způsob, jakým se použije. Například:
graph TD;
subgraph ConditionalAccessExpression
whole[a?.b = c]
end
subgraph
subgraph WhenNotNull
whole-->whenNotNull[".b = c"];
whenNotNull-->.b;
whenNotNull-->eq[=];
whenNotNull-->c;
end
subgraph OperatorToken
whole-->?;
end
subgraph Expression
whole-->a;
end
end
Složité příklady
class C
{
ref int M() => /*...*/;
}
void M1(C? c)
{
c?.M() = 42; // equivalent to:
if (c is not null)
c.M() = 42;
}
int? M2(C? c)
{
return c?.M() = 42; // equivalent to:
return c is null ? (int?)null : c.M() = 42;
}
M(a?.b?.c = d); // equivalent to:
M(a is null
? null
: (a.b is null
? null
: (a.b.c = d)));
return a?.b = c?.d = e?.f; // equivalent to:
return a?.b = (c?.d = e?.f); // equivalent to:
return a is null
? null
: (a.b = c is null
? null
: (c.d = e is null
? null
: e.f));
}
a?.b ??= c; // equivalent to:
if (a is not null)
{
if (a.b is null)
{
a.b = c;
}
}
return a?.b ??= c; // equivalent to:
return a is null
? null
: a.b is null
? a.b = c
: a.b;
Nevýhody
Volba uchovat přiřazení v rámci podmíněného přístupu přináší integrovanému vývojovému prostředí (IDE) další práci, protože obsahuje mnoho kódových cest, které musí pracovat zpětně od přiřazení k identifikaci toho, co je přiřazováno.
Alternatives
Místo toho bychom mohli udělat ?. syntakticky dítětem =. Aby bylo možné jakékoli zpracování = výrazů správně provést, je nutné si uvědomit podmíněnost pravé strany, pokud je na levé straně přítomno ?.. Také to dělá tak, aby struktura syntaxe neodpovídala tak silně sémantice.
Nevyřešené otázky
Designérské schůzky
- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-27.md#null-conditional-assignment
- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-31.md#null-conditional-assignment
- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-26.md#null-conditional-assignment
- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-28.md#increment-and-decrement-operators-in-null-conditional-access
C# feature specifications