Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Uyarı
Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.
Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar ilgili dil tasarım toplantısı (LDM) notlarında yakalanır.
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için
Şampiyonluk sorunu: https://github.com/dotnet/csharplang/issues/8677
Özet
Atamanın bir a?.b veya a?[b] ifadesi içinde koşullu olarak gerçekleşmesine izin verir.
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();
}
Motivasyon
Desteklenen sorunda çeşitli ilgi çekici kullanım örnekleri bulunabilir. Başlıca motivasyonlar şunlardır:
- Özellikler ve
Set()yöntemler arasındaki eşlik. - Kullanıcı arabirimi koduna olay işleyicileri ekleme.
Ayrıntılı tasarım
- Atamanın sağ tarafı yalnızca koşullu erişimin alıcısı null olmadığında değerlendirilir.
// 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();
- Tüm bileşik atama biçimlerine izin verilir.
a?.b -= M(); // ok
a?.b += M(); // ok
// etc.
- İfadenin sonucu kullanılırsa, ifadenin türünün bir değer türünde veya başvuru türünde olduğu bilinmelidir. Bu, koşullu erişimlerdeki mevcut davranışlarla tutarlıdır.
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
}
- Koşullu erişim ifadeleri hala lvalues değildir ve yine de örneğin bunlara
refuygulamak izni verilmez.
M(ref a?.b); // error
- Koşullu erişime yeni bir referans atamak yasaktır. Bunun temel nedeni, bir başvuru değişkenine koşullu olarak erişmenin tek yolunun bir başvuru alanı olması ve başvuru yapılarının null atanabilir değer türlerinde kullanılmasının yasak olmasıdır. İleride koşullu referans ataması için geçerli bir senaryo ortaya çıkarsa, o zaman destek ekleyebiliriz.
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'.
}
- Yapısöküm ataması yoluyla koşullu erişimlere atama yapmak mümkün değildir. İnsanların bunu yapmak istemelerinin nadir olacağını ve bunun yerine birden çok ayrı atama ifadesi üzerinde bunu yapması gerektiğinin önemli bir dezavantajı olmadığını tahmin ediyoruz.
(a?.b, c?.d) = (x, y); // error
- Artım/azaltma işleçleri desteklenmez.
a?.b++; // error
--a?.b; // error
- Koşullu erişimin alıcısı bir değer türü olduğunda bu özellik genellikle çalışmaz. Bunun nedeni, aşağıdaki iki durumdan birine denk gelecek olmasıdır:
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 bunu gevşetmeyi önerir, bu durumda a?.b = c, a, ve System.Nullable<T> salt okunur ayarlayıcıya sahip bir özellik olduğunda b için makul bir davranış tanımlayabiliriz.
Spesifikasyon
Null koşullu atama dil bilgisi aşağıdaki gibi tanımlanır:
null_conditional_assignment
: null_conditional_member_access assignment_operator expression
: null_conditional_element_access assignment_operator expression
Başvuru için bkz §11.7.7 ve §11.7.11.
Null koşullu atama bir ifade-deyiminde göründüğünde, semantiği aşağıdaki gibidir:
-
P?.A = Bile eşdeğerdirif (P is not null) P.A = B;, ancak yalnızcaPbir kez değerlendirilir. -
P?[A] = Bile eşdeğerdirif (P is not null) P[A] = B, ancak yalnızcaPbir kez değerlendirilir.
Aksi takdirde semantiği aşağıdaki gibidir:
-
P?.A = B,(P is null) ? (T?)null : (P.A = B)ile eşdeğerdir; buradaTP.A = B'ün sonuç türüdür ancakPyalnızca bir kez değerlendirilir. -
P?[A] = B,(P is null) ? (T?)null : (P[A] = B)ile eşdeğerdir; buradaTP[A] = B'ün sonuç türüdür ancakPyalnızca bir kez değerlendirilir.
Uygulama
Standarttaki dil bilgisi şu anda uygulamada kullanılan söz dizimi tasarımına kesin olarak karşılık gelmiyor. Bu özellik uygulandıktan sonra da böyle kalmasını bekliyoruz. Uygulamadaki söz dizimi tasarımının gerçekten değişmesi beklenmez; yalnızca kullanım şekli değişir. Örneğin:
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
Karmaşık örnekler
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;
Dezavantaj -ları
Atamayı koşullu erişimde tutma seçeneği, atamadan atanan öğeyi tanımlamak için geriye doğru çalışması gereken birçok kod yolunun bulunduğu IDE için bazı ek çalışmalar sağlar.
Alternatifler
Bunun yerine, ?. öğesini dizimsel olarak ='ün alt öğesi yapabiliriz. Bu, = ifadelerinin işlenmesi sırasında, solda ?. bulunduğunda sağ tarafın koşulluluğundan haberdar olunmasını gerektirir. Ayrıca söz diziminin yapısının semantikle tam olarak uyuşmamasını sağlar.
Çözülmemiş sorular
Tasarım toplantıları
- 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