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.
Not
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
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için
Şampiyon sorunu: https://github.com/dotnet/csharplang/issues/4665
Özet
C#, kullanıcıların taşma davranışını ihtiyaçlarına göre etkinleştirmeleri veya devre dışı bırakmaları için aşağıdaki kullanıcı tanımlı işleçlerin checked
varyantlarını tanımlamayı desteklemelidir.
-
++
ve--
birli operatörler §12.8.16 ve §12.9.6. - birli işleç
-
§12.9.3. -
+
,-
,*
ve/
ikili işleçleri , §12.10. - Açık dönüştürme işleçleri.
Motivasyon
Kullanıcının türü bildirmesinin ve bir işlecin hem işaretli hem de işaretsiz sürümlerini desteklemesinin hiçbir yolu yoktur. Bu, kütüphane ekibi tarafından açıklanan önerilen generic math
arabirimlerini kullanmak için çeşitli algoritmaları taşımayı zor hale getirir. Benzer şekilde, hataya neden olan değişiklikleri önlemek için dil aynı anda kendi desteğini göndermeden Int128
veya UInt128
gibi bir türü kullanıma sunmanız imkansız hale gelir.
Ayrıntılı tasarım
Sözdizimi
Operatörlerde dil bilgisi (§15.10), operatör belirtecinin hemen öncesinde checked
anahtar sözcüğünden sonra operator
anahtar sözcüğüne izin verilecek şekilde ayarlanacak.
overloadable_unary_operator
: '+' | 'checked'? '-' | '!' | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false'
;
overloadable_binary_operator
: 'checked'? '+' | 'checked'? '-' | 'checked'? '*' | 'checked'? '/' | '%' | '&' | '|' | '^' | '<<'
| right_shift | '==' | '!=' | '>' | '<' | '>=' | '<='
;
conversion_operator_declarator
: 'implicit' 'operator' type '(' type identifier ')'
| 'explicit' 'operator' 'checked'? type '(' type identifier ')'
;
Mesela:
public static T operator checked ++(T x) {...}
public static T operator checked --(T x) {...}
public static T operator checked -(T x) {...}
public static T operator checked +(T lhs, T rhs) {...}
public static T operator checked -(T lhs, T rhs) {...}
public static T operator checked *(T lhs, T rhs) {...}
public static T operator checked /(T lhs, T rhs) {...}
public static explicit operator checked U(T x) {...}
public static T I1.operator checked ++(T x) {...}
public static T I1.operator checked --(T x) {...}
public static T I1.operator checked -(T x) {...}
public static T I1.operator checked +(T lhs, T rhs) {...}
public static T I1.operator checked -(T lhs, T rhs) {...}
public static T I1.operator checked *(T lhs, T rhs) {...}
public static T I1.operator checked /(T lhs, T rhs) {...}
public static explicit I1.operator checked U(T x) {...}
Aşağıda kısa olması için, checked
anahtar sözcüğüne sahip bir işleç checked operator
ve içermeyen bir işleç regular operator
olarak adlandırılır. Bu koşullar, checked
formu olmayan işleçler için geçerli değildir.
Anlambilim
Bir işlemin sonucu hedef türde temsil edilemeyecek kadar büyük olduğunda, kullanıcı tanımlı bir checked operator
özel durum oluşturması beklenir. Çok büyük olmanın ne anlama geldiği, aslında hedef türün doğasına bağlıdır ve dil tarafından belirlenmemiştir. Genellikle oluşan özel durum bir System.OverflowException
olur, ancak dilin bununla ilgili belirli gereksinimleri yoktur.
Kullanıcı tanımlı bir regular operator
'nin, bir işlemin sonucu hedef türe sığmayacak kadar büyük olduğunda bir istisna oluşturmaması beklenir. Bunun yerine, kısaltılmış sonucu temsil eden bir örneğin döndürülmesi beklenir. Çok büyük olmak ve kesilmek ne anlama gelir sorusu, aslında hedef türün doğasına bağlıdır ve bu durum dil tarafından tanımlanmamıştır.
checked
formu desteklenecek olan tüm mevcut kullanıcı tanımlı işleçler regular operators
kategorisine girer. Birçoğunun yukarıda belirtilen semantiği izlemeyeceği, ancak anlam analizi amacıyla derleyicinin bunların olduğunu varsayacağı anlaşılmaktadır.
bir checked operator
içinde kontrollü ve kontrolsüz bağlam karşılaştırması
Bir checked operator
gövdesindeki işaretli veya işaretsiz bağlam, checked
anahtar sözcüğünün varlığından etkilenmez. Başka bir deyişle bağlam, işleç bildiriminin hemen başındaki bağlamla aynıdır. Algoritmanın bir bölümü varsayılan bağlamı kullanamıyorsa geliştiricinin bağlamı açıkça değiştirmesi gerekir.
Meta verilerdeki adlar
ECMA-335'in "I.10.3.1 Birli işleçler" bölümü, denetlenen , ve tekli işleçleri uygulayan yöntemlerin adları olarak ++
, --
, -
içerecek şekilde ayarlanır.
ECMA-335'in "I.10.3.2 İkili işleçler" bölümü, denetlenen , , ve ikili işleçleri uygulayan yöntemlerin adları olarak +
, -
, *
, /
içerecek şekilde ayarlanır.
ECMA-335'in "I.10.3.3 Dönüştürme işleçleri" bölümü, denetlenen açık dönüştürme işlecini uygulayan bir yöntemin adı olarak op_CheckedExplicit içerecek şekilde ayarlanır.
Tekli operatörler
Unary checked operators
§15.10.2kurallarına uyar.
Ayrıca, bir checked operator
bildirimi, bir regular operator
'in çift olarak bildirilmesini gerektirir (dönüş tipi de eşleşmelidir). Aksi takdirde derleme zamanı hatası oluşur.
public struct Int128
{
// This is fine, both a checked and regular operator are defined
public static Int128 operator checked -(Int128 lhs);
public static Int128 operator -(Int128 lhs);
// This is fine, only a regular operator is defined
public static Int128 operator --(Int128 lhs);
// This should error, a regular operator must also be defined
public static Int128 operator checked ++(Int128 lhs);
}
İkili işleçler
İkili checked operators
, §15.10.3kurallarına uyar.
Ayrıca, bir checked operator
bildirimi, bir regular operator
'in çift olarak bildirilmesini gerektirir (dönüş tipi de eşleşmelidir). Aksi takdirde derleme zamanı hatası oluşur.
public struct Int128
{
// This is fine, both a checked and regular operator are defined
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
// This is fine, only a regular operator is defined
public static Int128 operator -(Int128 lhs, Int128 rhs);
// This should error, a regular operator must also be defined
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
}
Aday kullanıcı tanımlı işleçler
Aday kullanıcı işleçleri (§12.4.6) bölümü aşağıdaki gibi ayarlanır (eklemeler/değişiklikler kalın yazı tipindedir).
bir tür T
ve operator op(A)
bir işlem verildiğinde, burada op
aşırı yüklenebilir bir işleç ve A
bir bağımsız değişken listesidir, T
için operator op(A)
tarafından sağlanan aday kullanıcı tanımlı işleç kümesi aşağıdaki gibi belirlenir:
-
T0
türünü belirleyin.T
nullable bir türse,T0
onun temel türüdür, değilseT0
T
'e eşittir. -
U
kullanıcı tanımlı işleç kümesini bulun. Bu küme şunlardan oluşur:-
unchecked
değerlendirme bağlamında,operator op
içindeki tüm normalT0
bildirimleri. -
checked
değerlendirme bağlamında, çift olarak eşleşenoperator op
bildirimine sahip normal bildirimler dışında,T0
içindeki tüm denetlenen ve normalchecked operator
bildirimleri.
-
-
operator op
'deki tümU
bildirimleri ve bu tür işleçlerin kaldırılan tüm biçimleri için, bağımsız değişken listesiyle ilgili olarak en az bir işleç (A
) varsa, aday işleçler kümesiT0
'deki tüm ilgili işleçlerden oluşur. - Aksi takdirde,
T0
object
ise, aday işleç kümesi boş olur. - Aksi takdirde,
T0
tarafından sağlanan aday işleçler kümesi,T0
doğrudan temel sınıfı veyaT0
bir tür parametresiyseT0
etkin temel sınıfı tarafından sağlanan aday işleçler kümesidir.
https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfacesarabirimlerdeki aday işleçler kümesi belirlenirken de benzer kurallar uygulanır.
§12.8.20
Örnek 1:
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'
Int128 r6 = unchecked(lhs * rhs);
}
public static void Divide(Int128 lhs, byte rhs)
{
// Resolves to `op_Division` - it is a better match than `op_CheckedDivision`
Int128 r4 = checked(lhs / rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
// Cannot be declared in C# - missing unchecked operator, but could be declared by some other language
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
public static Int128 operator checked /(Int128 lhs, int rhs);
public static Int128 operator /(Int128 lhs, byte rhs);
}
Örnek 2:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// error CS0034: Operator '+' is ambiguous on operands of type 'C2' and 'C3'
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
// Cannot be declared in C# - missing unchecked operator, but could be declared by some other language
public static C1 operator checked + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Örnek 3:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// error CS0034: Operator '+' is ambiguous on operands of type 'C2' and 'C3'
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
// Cannot be declared in C# - missing unchecked operator, but could be declared by some other language
public static C2 operator checked + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Dönüştürme işleçleri
Dönüşüm checked operators
, §15.10.4'de belirtilen kurallara uyar.
Ancak, checked operator
bildirimi için çift olarak regular operator
bildirimi gerekir. Aksi takdirde derleme zamanı hatası oluşur.
Aşağıdaki paragraf
Dönüştürme işlecinin imzası kaynak türünden ve hedef türünden oluşur. (Bu, iade türünün imzaya katıldığı tek üye biçimidir.) Dönüştürme işlecinin örtük veya açık sınıflandırması, işlecin imzasının bir parçası değildir. Bu nedenle, bir sınıf veya yapı aynı kaynak ve hedef türlerine sahip örtük ve açık dönüştürme işlecini bildiremez.
, bir türün aynı kaynak ve hedef türlerle işaretli ve normal açık dönüştürme biçimlerini bildirmesine izin verecek şekilde ayarlanır. Bir türün hem örtük hem de aynı kaynak ve hedef türlerine sahip denetlenen açık dönüştürme işlecini bildirmesine izin verilmez.
Kullanıcı tanımlı açık dönüştürmelerin işlenmesi
§10.5.5üçüncü madde işareti:
- Kullanıcı tanımlı ve kaldırılmış geçerli dönüşüm operatörleri kümesini bul
U
. Bu küme,D
sınıfları veya yapıları tarafından belirtilen veS
'in kapsadığı veya kapsandığı bir türden,T
'nin kapsadığı veya kapsandığı bir türe dönüştüren kullanıcı tanımlı ve kaldırılan örtük veya açık dönüştürme operatörlerinden oluşur.U
boşsa, dönüştürme tanımsız olur ve derleme zamanı hatası oluşur.
aşağıdaki madde işareti noktalarıyla değiştirilecektir:
-
U0
dönüştürme işleçleri kümesini bulun. Bu küme şunlardan oluşur:-
unchecked
değerlendirme bağlamında,D
sınıflar veya yapılar tarafından bildirilen kullanıcı tanımlı örtük veya normal açık dönüştürme işleçleri kullanılır. -
checked
değerlendirme bağlamında,D
sınıflar veya yapılar tarafından bildirilen kullanıcı tanımlı örtük veya normal/denetlenmiş açık dönüştürme işleçleri, aynı bildirim türü içindeki çift yönlü eşleştirmechecked operator
bildirimine sahip normal açık dönüştürme işleçleri dışında.
-
- Kullanıcı tanımlı ve kaldırılmış geçerli dönüşüm operatörleri kümesini bul
U
. Bu küme,tarafından kapsadığı veya tarafından kapsadığı bir türe dönüştüren kullanıcı tanımlı ve kaldırılmış örtük veya açık dönüştürme işleçlerinden oluşur. U
boşsa, dönüştürme tanımsız olur ve derleme zamanı hatası oluşur.
§11.8.20
İşleçlerin uygulanması
checked operator
bir regular operator
uygulamaz ve tam tersi de geçerlidir.
Linq İfade Ağaçları
Checked operators
Linq İfade Ağaçlarında desteklenecektir. İlgili UnaryExpression
ile bir /BinaryExpression
MethodInfo
düğümü oluşturulacak.
Aşağıdaki fabrika yöntemleri kullanılacaktır:
public static UnaryExpression NegateChecked (Expression expression, MethodInfo? method);
public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo? method);
public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo? method);
public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo? method);
public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo? method);
C# ifadesinin ifade ağaçlarındaki atamaları desteklemediğini, bu nedenle işaretli artış/azaltmanın da desteklenmediğini unutmayın.
Kontrollü bölme için fabrika yöntemi yoktur. Bununla ilgili açık bir soru var - Linq İfade Ağaçlarında Denetlenen Bölüm.
Dinamik
CoreCLR'de dinamik çağrıda kontrollü operatörler için destek eklemenin maliyetini araştıracağız ve maliyet çok yüksek değilse bir uygulama gerçekleştireceğiz. Bu, https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md'den bir alıntıdır.
Dezavantaj -ları
Bu, dile ekstra karmaşıklık ekler ve kullanıcıların türlerinde çeşitli geriye dönük uyumsuz değişiklikler yapmasına olanak tanır.
Alternatif
Kitaplıkların kullanıma sunmayı planladığı genel matematik arabirimleri adlandırılmış yöntemleri (AddChecked
gibi) kullanıma açabilir. Birincil dezavantajı, bunun daha az okunabilir/sürdürülebilir olması ve işleçler etrafında dil önceliği kurallarından yararlanmamasıdır.
Bu bölümde ele alınan ancak uygulanmayan alternatifler listelenmiştir
checked
anahtar sözcüğünü yerleştirme
Alternatif olarak checked
anahtar sözcüğü, operator
anahtar sözcüğünden hemen önceki yere taşınabilir:
public static T checked operator ++(T x) {...}
public static T checked operator --(T x) {...}
public static T checked operator -(T x) {...}
public static T checked operator +(T lhs, T rhs) {...}
public static T checked operator -(T lhs, T rhs) {...}
public static T checked operator *(T lhs, T rhs) {...}
public static T checked operator /(T lhs, T rhs) {...}
public static explicit checked operator U(T x) {...}
public static T checked I1.operator ++(T x) {...}
public static T checked I1.operator --(T x) {...}
public static T checked I1.operator -(T x) {...}
public static T checked I1.operator +(T lhs, T rhs) {...}
public static T checked I1.operator -(T lhs, T rhs) {...}
public static T checked I1.operator *(T lhs, T rhs) {...}
public static T checked I1.operator /(T lhs, T rhs) {...}
public static explicit checked I1.operator U(T x) {...}
Veya işleç değiştirici kümesine taşınabilir:
operator_modifier
: 'public'
| 'static'
| 'extern'
| 'checked'
| operator_modifier_unsafe
;
public static checked T operator ++(T x) {...}
public static checked T operator --(T x) {...}
public static checked T operator -(T x) {...}
public static checked T operator +(T lhs, T rhs) {...}
public static checked T operator -(T lhs, T rhs) {...}
public static checked T operator *(T lhs, T rhs) {...}
public static checked T operator /(T lhs, T rhs) {...}
public static checked explicit operator U(T x) {...}
public static checked T I1.operator ++(T x) {...}
public static checked T I1.operator --(T x) {...}
public static checked T I1.operator -(T x) {...}
public static checked T I1.operator +(T lhs, T rhs) {...}
public static checked T I1.operator -(T lhs, T rhs) {...}
public static checked T I1.operator *(T lhs, T rhs) {...}
public static checked T I1.operator /(T lhs, T rhs) {...}
public static checked explicit I1.operator U(T x) {...}
unchecked
anahtar sözcüğü
aşağıdaki olası anlamlara sahip unchecked
anahtar sözcüğüyle aynı konumda checked
anahtar sözcüğü desteklemeye yönelik öneriler vardı:
- Yalnızca operatörün normal doğasını açıkça yansıtmak veya
- Belki de
unchecked
bağlamında kullanılması gereken bir işlecin farklı bir türünü tanımlamaktır. Dil, yıkıcı değişikliklerin sayısını sınırlamaya yardımcı olmak içinop_Addition
,op_CheckedAddition
veop_UncheckedAddition
'yi destekleyebilir. Bu, çoğu kodda gerekli olmayabilecek başka bir karmaşıklık katmanı ekler.
ECMA-335'te işleç adları
Alternatif olarak, işleç adları op_UnaryNegationChecked, op_AdditionChecked, op_SubtractionChecked, op_MultiplyChecked, op_DivisionCheckedolabilir ve sonunda Checked bulunabilir. Ancak, adları işleç sözcüğüyle sonlandırmak için oluşturulmuş bir desen zaten var gibi görünüyor. Örneğin, op_UnsignedRightShift işleci yerine bir op_RightShiftUnsigned işleci vardır.
Checked operators
bir unchecked
bağlamında kullanılamaz
Derleyici, unchecked
bağlamında üye bulma işlemi yaparken kullanıcı tanımlı aday işleçleri bulmak için checked operators
'i yoksayabilir. Yalnızca bir checked operator
tanımlayan meta verilerle karşılaşılırsa bir derleme hatası oluşur.
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'
Int128 r5 = unchecked(lhs * rhs);
}
}
public struct Int128
{
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
}
checked
bağlamında daha karmaşık işleç arama ve aşırı yükleme çözümleme kuralları
Derleyici, checked
bağlamında kullanıcı tanımlı aday işleçleri bulmak için üye araması gerçekleştirirken Checked
ile biten geçerli işleçleri de dikkate alır. Başka bir ifadeyle, derleyici ikili ekleme işleci için uygun işlev üyelerini bulmaya çalışırsa hem op_Addition
hem de op_AdditionChecked
arar. Geçerli tek işlev üyesi bir checked operator
ise, o kullanılacaktır. Hem regular operator
hem de checked operator
varsa ve eşit oranda uygulanabilirse checked operator
tercih edilir. Hem regular operator
hem de checked operator
varsa ama regular operator
tam olarak eşleşiyorsa ancak checked operator
eşleşmediyse, derleyici regular operator
tercih eder.
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
}
public static void Multiply(Int128 lhs, byte rhs)
{
// Resolves to `op_Multiply` even though `op_CheckedMultiply` is also applicable
Int128 r4 = checked(lhs * rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
public static Int128 operator checked *(Int128 lhs, int rhs);
public static Int128 operator *(Int128 lhs, byte rhs);
}
Aday kullanıcı tanımlı işleçler kümesini oluşturmanın bir başka yolu daha
Tekli işleç aşırı yükleme çözümlemesi
regular operator
unchecked
değerlendirme bağlamıyla eşleşirse, checked operator
checked
değerlendirme bağlamıyla eşleşirse ve checked
formuna sahip olmayan bir operatör (örneğin, +
) her iki bağlamla da eşleşirse, §12.4.4 - Tekli işleç aşırı yükleme çözümlemesi'ndeki ilk madde işareti:
- İşlem
X
içinoperator op(x)
tarafından sağlanan aday kullanıcı tanımlı işleç kümesi, §12.4.6 - Aday kullanıcı tanımlı işleçlerile belirlenir.
aşağıdaki iki madde işaretiyle değiştirilir:
- İşlem
X
operator op(x)
eşleşmesi için tarafından sağlanan aday kullanıcı tanımlı işleçler kümesi, Aday kullanıcı tanımlı işleçlerin kuralları kullanılarak belirlenir. - Kullanıcı tanımlı aday işleç kümesi boş değilse, bu işlem için aday işleç kümesi olur. Aksi takdirde,
X
tarafından,operator op(x)
işlemi için karşıt kontrol edilmiş/kontrol edilmemiş bağlam'e uyan aday kullanıcı tanımlı işleçler kümesi, §12.4.6 - Aday kullanıcı tanımlı işleçlerkuralları kullanılarak belirlenir.
İkili işleç aşırı yükleme çözümlemesi
regular operator
unchecked
değerlendirme bağlamıyla eşleşirse, checked operator
checked
değerlendirme bağlamı ile eşleşir ve checked
formu olmayan bir işleç (örneğin, %
) her iki bağlamla da eşleşir; içindeki ilk madde işareti §12.4.5 - İkili işleç aşırı yükleme çözümlemesi:
- İşlem
X
içinY
veoperator op(x,y)
tarafından sağlanan aday kullanıcı tanımlı işleç kümesi belirlenir. Küme, her biriX
kuralları kullanılarak belirlenen,Y
tarafından sağlanan aday işleçleri ile tarafından sağlanan aday işleçlerinin birleşiminden oluşur.X
veY
aynı türdeyse veyaX
veY
ortak bir temel türden türetilmişse, paylaşılan aday işleçleri birleştirilmiş kümede yalnızca bir kez gerçekleşir.
aşağıdaki iki madde işaretiyle değiştirilir:
- geçerli işaretli/işaretsiz bağlamına uyum sağlayan
işlemi için ve tarafınca sağlanan aday kullanıcı tanımlı işleçler kümesi belirlenir. Küme, her biri X
kuralları kullanılarak belirlenen,Y
tarafından sağlanan aday işleçleri ile tarafından sağlanan aday işleçlerinin birleşiminden oluşur.X
veY
aynı türdeyse veyaX
veY
ortak bir temel türden türetilmişse, paylaşılan aday işleçleri birleştirilmiş kümede yalnızca bir kez gerçekleşir. - Kullanıcı tanımlı aday işleç kümesi boş değilse, bu işlem için aday işleç kümesi olur. Aksi takdirde, kontrol edilen/kontrolsüz bağlam ile eşleşen operasyon
için ve tarafından sağlanan aday kullanıcı tanımlı işleçler kümesi belirlenir. Küme, her biri X
kuralları kullanılarak belirlenen,Y
tarafından sağlanan aday işleçleri ile tarafından sağlanan aday işleçlerinin birleşiminden oluşur.X
veY
aynı türdeyse veyaX
veY
ortak bir temel türden türetilmişse, paylaşılan aday işleçleri birleştirilmiş kümede yalnızca bir kez gerçekleşir.
Örnek 1:
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = unchecked(lhs * rhs);
}
public static void Divide(Int128 lhs, byte rhs)
{
// Resolves to `op_CheckedDivision`
Int128 r4 = checked(lhs / rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
public static Int128 operator checked /(Int128 lhs, int rhs);
public static Int128 operator /(Int128 lhs, byte rhs);
}
Örnek 2:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C1.op_CheckedAddition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Örnek 3:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Örnek #4:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C1.op_CheckedAddition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C2.op_Addition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, byte y) => new C1();
}
class C2 : C1
{
public static C2 operator + (C2 x, int y) => new C2();
}
Örnek #5:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C1.op_Addition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, int y) => new C1();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, byte y) => new C2();
}
Kullanıcı tanımlı açık dönüştürmelerin işlenmesi
regular operator
unchecked
değerlendirme bağlamı ile ve checked operator
checked
değerlendirme bağlamı ile eşleştiğini varsayarsak, kullanıcı tanımlı dönüştürmelerin değerlendirilmesi §10.5.3 içindeki üçüncü madde:
- Kullanıcı tanımlı ve kaldırılmış geçerli dönüşüm operatörleri kümesini bul
U
. Bu küme,D
sınıfları veya yapıları tarafından belirtilen veS
'in kapsadığı veya kapsandığı bir türden,T
'nin kapsadığı veya kapsandığı bir türe dönüştüren kullanıcı tanımlı ve kaldırılan örtük veya açık dönüştürme operatörlerinden oluşur.U
boşsa, dönüştürme tanımsız olur ve derleme zamanı hatası oluşur.
aşağıdaki madde işareti noktalarıyla değiştirilecektir:
geçerli işaretli/işaretsiz bağlamla eşleşen geçerli kullanıcı tanımlı ve kaldırılmış açık dönüştürme işleçleri kümesini bulun. Bu küme, D
sınıfları veya yapıları tarafından bildirilen ve geçerli işaretli/işaretsiz bağlam eşleşen veS
tarafından kapsayan veyaT
kapsayan bir türe dönüştüren kullanıcı tanımlı ve kaldırılmış açık dönüştürme işleçlerinden oluşur.- Kullanıcı tanımlı ve kaldırılmış açık dönüştürme işleçlerinden, karşıt denetimli/denetimsiz bağlama uyan kümesini bulun ,,
U1
.U0
boş değilseU1
boş olur. Aksi takdirde, bu küme,D
sınıfları veya yapıları tarafından bildirilen kullanıcı tanımlı ve yükseltilmiş açık dönüştürme işleçlerinden oluşur ve zıt işaretli/işaretsiz bağlam ile eşleşir veS
tarafından kapsanan veya onları kapsayan bir türdenT
tarafından kapsanan veya onları kapsayan bir türe dönüştürülür. - Kullanıcı tanımlı ve kaldırılmış geçerli dönüşüm operatörleri kümesini bul
U
. Bu küme,U0
,U1
veD
sınıfları veya yapıları tarafından bildirilen veS
ile kapsanan veyaT
ile kapsayan bir türe dönüştüren kullanıcı tanımlı ve kaldırılmış örtük dönüştürme operatörlerinden oluşur.U
boşsa, dönüştürme tanımsız olur ve derleme zamanı hatası oluşur.
Aday kullanıcı tanımlı işleçler kümesini oluşturmanın bir başka başka yolu daha
Tekli işleç aşırı yükleme çözümlemesi
§12.4.4
- İşlem
X
içinoperator op(x)
tarafından sağlanan aday kullanıcı tanımlı işleç kümesi, aşağıdaki "Aday kullanıcı tanımlı işleçler" bölümü kuralları kullanılarak belirlenir. Küme, işaretli formda en az bir işleç içeriyorsa, normal formdaki tüm işleçler kümeden kaldırılır.
§12.8.20 bölümü, işaretli/işaretsiz bağlamın birli işleç aşırı yükleme çözünürlüğü üzerindeki etkisini yansıtacak şekilde ayarlanacaktır.
İkili işleç aşırı yükleme çözümlemesi
§12.4.5 içinde
- İşlem
X
içinY
veoperator op(x,y)
tarafından sağlanan aday kullanıcı tanımlı işleç kümesi belirlenir. Küme,X
tarafından sağlanan aday işleçleri ileY
tarafından sağlanan aday işleçlerinin birleşiminden oluşur ve her biri aşağıdaki "Aday kullanıcı tanımlı işleçler" bölümü kullanılarak belirlenir.X
veY
aynı türdeyse veyaX
veY
ortak bir temel türden türetilmişse, paylaşılan aday işleçleri birleştirilmiş kümede yalnızca bir kez gerçekleşir. Küme, işaretli formda en az bir işleç içeriyorsa, normal formdaki tüm işleçler kümeden kaldırılır.
İşaretli ve işaretlenmemiş işleçler §12.8.20 bölümü, denetlenen/denetlenmeyen bağlamın ikili işleç aşırı yükleme çözümlemesi üzerindeki etkisini yansıtacak şekilde ayarlanır.
Aday kullanıcı tanımlı işleçler
§12.4.6 - Aday kullanıcı tanımlı işleçler bölümü aşağıdaki gibi ayarlanır (eklemeler kalındır).
bir tür T
ve operator op(A)
bir işlem verildiğinde, burada op
aşırı yüklenebilir bir işleç ve A
bir bağımsız değişken listesidir, T
için operator op(A)
tarafından sağlanan aday kullanıcı tanımlı işleç kümesi aşağıdaki gibi belirlenir:
-
T0
türünü belirleyin.T
nullable bir türse,T0
onun temel türüdür, değilseT0
T
'e eşittir. - Tüm
bildirimleri, değerlendirme bağlamında ve yalnızca değerlendirme bağlamındaki normal formlarında ve bu işleçlerin kaldırılan tüm formlarında, denetlenen ve normal formlarında , bağımsız değişken listesiyle ilgili olarak en az bir işleç ( §12.6.4.2 ) geçerliyse, aday işleçler kümesiiçindeki bu tür geçerli işleçlerden oluşur. - Aksi takdirde,
T0
object
ise, aday işleç kümesi boş olur. - Aksi takdirde,
T0
tarafından sağlanan aday işleçler kümesi,T0
doğrudan temel sınıfı veyaT0
bir tür parametresiyseT0
etkin temel sınıfı tarafından sağlanan aday işleçler kümesidir.
https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfacesarabirimlerdeki aday işleçler kümesi belirlenirken benzer filtreleme uygulanır.
§12.8.20 bölümü, işaretli/işaretsiz bağlamın birli ve ikili işleç aşırı yükleme çözümlemesi üzerindeki etkisini yansıtacak şekilde ayarlanır.
Örnek 1:
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'
Int128 r5 = unchecked(lhs * rhs);
}
public static void Divide(Int128 lhs, byte rhs)
{
// Resolves to `op_CheckedDivision`
Int128 r4 = checked(lhs / rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
public static Int128 operator checked /(Int128 lhs, int rhs);
public static Int128 operator /(Int128 lhs, byte rhs);
}
Örnek 2:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C1.op_CheckedAddition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Örnek 3:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Örnek #4:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C2.op_Addition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C2.op_Addition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, byte y) => new C1();
}
class C2 : C1
{
public static C2 operator + (C2 x, int y) => new C2();
}
Örnek #5:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C1.op_Addition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, int y) => new C1();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, byte y) => new C2();
}
Kullanıcı tanımlı açık dönüştürmelerin işlenmesi
§10.5.5üçüncü madde işareti:
- Kullanıcı tanımlı ve kaldırılmış geçerli dönüşüm operatörleri kümesini bul
U
. Bu küme,D
sınıfları veya yapıları tarafından belirtilen veS
'in kapsadığı veya kapsandığı bir türden,T
'nin kapsadığı veya kapsandığı bir türe dönüştüren kullanıcı tanımlı ve kaldırılan örtük veya açık dönüştürme operatörlerinden oluşur.U
boşsa, dönüştürme tanımsız olur ve derleme zamanı hatası oluşur.
aşağıdaki madde işareti noktalarıyla değiştirilecektir:
- geçerli kullanıcı tanımlı ve yükseltilmiş açık dönüştürme işleçleri kümesini bulun
U0
. Bu küme, sınıflar veya yapılar tarafındanD
değerlendirme bağlamında denetlenen ve normal formlarındachecked
bildirilen kullanıcı tanımlı ve kaldırılmış açık dönüştürme işleçlerinden oluşur ve yalnızcaunchecked
değerlendirme bağlamında normal biçimlerinde veS
tarafından kapsadığı veyaT
tarafından kapsadığı bir türe dönüştürülür. -
U0
işaretli formda en az bir işleç içeriyorsa, normal formdaki tüm işleçler kümeden kaldırılır. - Kullanıcı tanımlı ve kaldırılmış geçerli dönüşüm operatörleri kümesini bul
U
. Bu küme,U0
işleçlerinden veD
sınıfları veya yapıları tarafından bildirilen,S
'yi kapsayan veya ondan kapsanan bir tipten,T
'ü kapsayan veya ondan kapsanan bir türe dönüştüren, kullanıcı tanımlı ve yükseltilmiş örtük dönüştürme işleçlerinden oluşur.U
boşsa, dönüştürme tanımsız olur ve derleme zamanı hatası oluşur.
§12.8.20
bir checked operator
içinde kontrollü ve kontrolsüz bağlam karşılaştırması
Derleyici, bir checked operator
varsayılan bağlamını kontrollü olarak değerlendirebilir. Eğer algoritmasının bir bölümü unchecked
'e katılmaması gerekiyorsa, geliştiricinin checked context
'ı açıkça kullanması gerekir. Ancak, checked
/unchecked
belirteçlerin işleçlerde düzenleyici olarak gövde içindeki bağlamı ayarlamasına izin vermeye başlarsak bu işlem gelecekte iyi çalışmayabilir. Değiştirici ve anahtar sözcük birbiriyle çelişebilir. Ayrıca, bir regular operator
için aynı işlemi (varsayılan bağlamı işaretlenmemiş olarak kabul et) yapamayız çünkü bu uyumsuzluk sorununa yol açar.
Çözülmemiş sorular
Dil, yöntemlerde checked
ve unchecked
değiştiricilere izin vermelidir (örn. static checked void M()
)?
Bu, bunu gerektiren yöntemler için iç içe yerleştirme düzeylerinin kaldırılmasına izin verir.
Linq Expression Trees'de kontrol edilmiş bölüm
Denetimli bir bölme düğümü oluşturmak için bir fabrika yöntemi yoktur ve ExpressionType.DivideChecked
üyesi de yoktur.
MethodInfo
yöntemine işaret eden op_CheckedDivision
düzenli bölme düğümü oluşturmak için aşağıdaki fabrika yöntemini kullanmaya devam edebiliriz.
Tüketicilerin bağlamı çıkarsamak için adı kontrol etmesi gerekir.
public static BinaryExpression Divide (Expression left, Expression right, MethodInfo? method);
§12.8.20 bölümünde işaretli/işaretsiz değerlendirme bağlamından etkilenen işleçlerden biri olarak /
işleci listelense de IL'nin işaretli bölme gerçekleştirmek için özel bir işlem kodu yoktur.
Derleyici, bugün bağlamdan bağımsız olarak her zaman fabrika metodunu kullanır.
Teklifi: Denetlenen kullanıcı tanımlı devision, Linq expression Trees içinde desteklenmeyecektir.
(Çözüldü) Örtük kontrollü dönüştürme işleçlerini desteklemeli miyiz?
Genel olarak, örtük dönüştürme işleçlerinin istisna fırlatması beklenmez.
Teklifi: Hayır.
Çözümü: Onaylandı - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md#checked-implicit-conversions
Tasarım toplantıları
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-14.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-23.md
C# feature specifications